= Here is a list of Power Shell Scripts that are too cool to ignore =

<<TableOfContents>>

For the uninitiated: 

|| Symbol || Meaning ||
|| %  || shortcut for foreach object ||
|| $_ || current object in the pipeline ||
|| Get-Help [Powershell command] || Gives you help on that powershell command ||
|| Get-Member || Will list the fields of the object you send it ||
|| Sort-Object -Property [property name] || Will sort the objects you send in by the property name(s) which can be a comma separated list ||
|| Where-Object {$_.property -like '*string*'} || Will filter the objects. Also short cut notation: ? {$_.property -like '*string*'}  ||
|| Get-Command -Module PSWindowsUpdate || Lists all the commands in the PSWindowsUpdate module ||

= Windows =

== Printing all docx and pdf files in a directory ==

{{{#!highlight powershell
$Path = "PATH WERE FILES EXIST"
cd $Path
$DocList = Get-ChildItem -Path $Path -filter *.docx -file -ErrorAction SilentlyContinue
$PdfList = Get-ChildItem -Path $Path -filter *.pdf -file -ErrorAction SilentlyContinue
foreach ($f in $DocList) {
    Start-Process -FilePath $f -Verb print
    Write-Host "Printing DOCX: $f"
}
foreach ($p in $PdfList) {
    Start-Process -FilePath $p -Verb print
    Write-Host "Printing PDF: $p"
}
}}}

== Basic filtering of services ==

{{{#!highlight powershell
Get-Service | ? { ($_.Status -eq "Running") -and ($_.StartType -eq "Manual") }
}}}

== Expand all zip files into directories with zip name ==

{{{#!highlight powershell
$list = Get-ChildItem | ? { $_.Name -like "*.zip" } | select Name
foreach ($line in $list) {
    $parts = $line.Name.Split(".")
    $outDir = ".\" + $parts[0]
    $inFile = $line.Name
    mkdir $outDir
    Expand-Archive $inFile -DestinationPath $outDir 
}
}}}


== List of Listening Ports with their owning programs ==

{{{#!highlight powershell
$listening = (Get-NetTCPConnection | ? {($_.State -eq "Listen") -and ($_.RemoteAddress -eq "0.0.0.0")})
foreach ($l in $listening) {
    $procid = $l.OwningProcess
    $proc = Get-Process -PID $procid | SELECT ID,ProcessName
    Write-Host "|| TCP ||" $($u.LocalAddress) "||" $($l.LocalPort) "||" $($procid) "||" $proc.ProcessName "||"
}

$udp = Get-NetUDPEndpoint
foreach ($u in $udp) {
    $procid = $u.OwningProcess
    $proc = Get-Process -PID $procid | SELECT ID,ProcessName
    Write-Host "|| UDP ||" $($u.LocalAddress) "||" $($u.LocalPort) "||" $($procid) "||" $proc.ProcessName "||"
}
}}}

== List Memory Installed ==

{{{#!highlight powershell
Get-WmiObject win32_physicalmemory | Format-Table Manufacturer,Banklabel,Configuredclockspeed,Devicelocator,Capacity,Serialnumber -autosize
}}}

== List object from Registry - namely version of .NET installed ==

{{{#!highlight powershell
gci 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' | sort pschildname -des | foreach-object {$_.name; $_.GetValue("Version");}
}}}

== Remote Session / Shell ==
{{{#!highlight powershell
Enter-PSSession -Computer [ComputerName]
}}}

== Remote commands ==

{{{#!highlight powershell
Invoke-Command -ComputerName eve -ScriptBlock { date }
}}}

== Replace a string in a file using a regular expression ==

So I downloaded a bunch of files from "the way back machine" site and I needed to update the hard-coded links to be relative site links. The following little script did it for me. 

{{{#!highlight powershell

$files = ls Level*.html
foreach ($item in $files) {
    (Get-Content -path $item) | % { $_ -Replace '(https://web.archive.org/nebula/level)([0123456789]{2})/', 'Level$2.html' } | Set-Content $item
} 

}}}

== Windows Backup Setup ==

Suppose that we have added a new disk for local backup purposes and that it is Disk 1. 

{{{#!highlight powershell
Add-WindowsFeature -Name Windows-Server-Backup
$policy = New-WBPolicy #Note that this is the backup policy, its like a job, but you can only have one of these daily backups weird huh? Yeah, I'll show you a different way later!
Add-WBSystemState -Policy $policy
$volumes = Get-WBVolume -CriticalVolumes
Add-WBVolume -Policy $policy -Volume $volumes
$disks = GEt-WBDisk
$target = New-WBBackupTarget -Disk $disks[1]
Add-WBBackupTarget -Policy $policy -Target $target
Set-WBSchedule -Policy $policy -Schedule "01:30" #Daily at 1:30 AM
Set-WBPolicy -Policy $policy #save this as the default policy, and answer Y to the format backup storage disk.
}}}

== Getting Rid of Pesky Service Not Running Errors ==

Did you ever look at your server dashboard and see a big fat red mark next to services only to find out that it is a service that will just quit again if you run it. You look into it and, no you don't need it!!! Two such services are:

 * OneSyncSvc
 * WpnUserService

Here is how to turn them off:

{{{#!highlight powershell
Set-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\OneSyncSvc*" -Name "Start" -Value 4
Set-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WpnUserService*" -Name "Start" -Value 4
}}}

If you just want these to be "Manual" instead of "Disabled" use a value of 3 instead of 4. 


= AD Scripts =

== Add RSAT tools to Windows 10 ==

{{{#!highlight powershell
Get-WindowsCapability -Name RSAT* -Online | Add-WindowsCapability -Online
}}}

OR Use Choco: https://chocolatey.org (Note: in 2024 using Windows 11 Pro Education, chocolatey refused to install because it was a version it didn't expect)
{{{#!highlight powershell
c:\> choco install -y rsat
}}}

== Install App Compatibility on Server Core ==

 1. Download the ISO (or if you are using my VM infrastructure, its already available, just load it into your DVD drive)

{{{#!highlight powershell
Add-WindowsCapability -Online -Name ServerCore.AppCompatibility -Source D:\LanguagesAndOptionalFeatures -LimitAccess
}}}

OR If you are lucky, you can try this one:

{{{#!highlight powershell
Add-WindowsCapability -Online -Name ServerCore.AppCompatibility~~~~0.0.1.0
}}}

Don't forget to eject the DVD. 

== List FSMO roles and Global Catalog servers ==

{{{#!hightlight powershell
Get-ADDomain | Select-Object InfrastructureMaster, RidMaster, PDCEmulator
Get-ADForest | Select-Object DomainNamingMaster, SchemaMaster
Get-ADDomainController -Filter {IsGlobalCatalog -eq $true} | Select-Object Hostname
}}}

OR On a domain controller:
{{{
c:\> netdom query fsmo
}}}

== Add User to the Active Directory as a batch ==

My preference is to add a user by creating a spreadsheet using the following commands. 

{{{#!highlight powershell
#Install-PackageProvider -Name Nuget -Force
#Install-Module ImportExcel -Scope CurrentUser
$userlist = Import-Excel -Path C:\Users\Administrator\Desktop\Lab03.xlsx

foreach ($user in $userlist)
{
    if ($user.Name)
    {
        if ($user.Manager -eq "None") 
        {
            New-ADUser -Name $user.Name -GivenName $user.GivenName -Surname $user.SurName `
            -SamAccountName $user.Username `
            -Path $user.OU `
            -AccountPassword (ConvertTo-SecureString "Hello123!@#" -AsPlainText -Force) `
            -Enabled $true `
            -Organization "CRT" `
            -Title $user.Position `
            -Department "Meneal Labor" `
            -Company "CRT" `
            -PasswordNeverExpires $true -ChangePasswordAtLogon $false
        }
        else {
            $manager = Get-ADUser -Filter {name -eq "Thomas Watson"}
            New-ADUser -Name $user.Name -GivenName $user.GivenName -Surname $user.SurName `
                -SamAccountName $user.Username `
                -Path $user.OU `
                -AccountPassword (ConvertTo-SecureString "Hello123!@#" -AsPlainText -Force) `
                -Enabled $true `
                -Organization "CRT" `
                -Title $user.Position `
                -Manager $manager `
                -Department "Meneal Labor" `
                -Company "CRT" `
                -PasswordNeverExpires $true -ChangePasswordAtLogon $false
        }
    }
}

Add-ADGroupMember -Identity Students -Members ab
}}}

See: [[attachment:Sample Add students accounts for Powershell.xlsx|Excel Example]]

== List of AD accounts and the last time they logged in and created date ==

{{{#!highlight powershell
# This method looks like it should work, but LastLogon is stored at each domain controller, and the domain controller you are 
# using, may not have ever been logged into by the user
#Get-ADUser -Filter * -SearchBase "dc=home,dc=scotnpatti,dc=com" -ResultPageSize 0 -Prop CN,samaccountname,lastLogonTimestamp | 
#     select CN, samaccountname,@{n="lastLogonDate";e={[datetime]::FromFileTime($_.LastLogonTimestamp)}} 

# INSTEAD USE THIS METHOD 
# NOTE: if run on a domain controller, it must be run as an elevated user. It appears to run fine from a client without elevated privileges
#To get the correct created dates, you must run this script from an elevated prompt or NOT ON A DOMAIN CONTROLLER
Import-Module ActiveDirectory
function Get-LastLogonEvents
{
    $UserList = New-Object System.Collections.ArrayList
    $dcs = Get-ADDomainController -Filter {Name -like "*"}
    $users = Get-ADUser -Filter *
    foreach($user in $users)
    {
        $time = 0
        $created = Get-Date -Date "8/10/2000 12:00:00 AM"
        foreach($dc in $dcs)
        {
            $hostname = $dc.HostName
            $aduser = Get-ADUser $user.SamAccountName -Properties whenCreated
            $currentUser = $aduser | Get-ADObject -Server $hostname -Properties lastLogon, lastLogonTimestamp
            if($currentUser.LastLogon -gt $time)
            {
                $time = $currentUser.LastLogon
            }
            if($currentUser.LastLogonTimeStamp -gt $time)
            {
                $time = $currentUser.LastLogonTimeStamp
            }
            if($aduser.whenCreated -gt $created)
            {
                $created = $aduser.whenCreated
            }
        }
        
        $dt = [DateTime]::FromFileTime($time)
        $temp = New-Object System.Object
        $temp | Add-Member -MemberType NoteProperty -Name "SamAccountName" -Value $user.SamAccountName
        $temp | Add-Member -MemberType NoteProperty -Name "LastLogon" -Value $dt
        $temp | Add-Member -MemberType NoteProperty -Name "Created" -Value $created
        $UserList.Add($temp) | Out-Null
        $time = 0
    }
    return $UserList
}
$myList = Get-LastLogonEvents | Sort-Object Created,LastLogon | Select SamAccountName, LastLogon, Created
#Write-Output $myList 
$myList | Export-Csv -Path "C:\Users\scot\Desktop\Users12-14-2021.csv"
}}}

== Delete AD User accounts that have not been used in X days ==

{{{#!highlight powershell
$DaysAgo = (Get-Date).AddDays(-180)
#Get-ADUser -Filter {Enabled -eq $True} -Properties LastLogonDate | ? {($_.LastLogonDate -le $DaysAgo)  } | FT Name, SamAccountName, DistinguishedName, LastLogonDate
Get-ADUser -Filter {Enabled -eq $True} -Properties LastLogonDate | ? {($_.LastLogonDate -le $DaysAgo)  } | Remove-ADUser -Confirm
}}}

== Delete AD Computer accounts that have not been used in X days ==
{{{#!highlight powershell
$YearAgo = (Get-Date).AddDays(-370)
Get-ADComputer -Filter * -Properties * | ? {$_.LastLogonDate -le $YearAgo } | Remove-ADObject -Recursive -Confirm 
#Get-ADComputer -Filter * -Properties * | ? {$_.LastLogonDate -le $YearAgo } | FT Name, LastLogonDate -AutoSize
}}}

== List AD Computer accounts and the last time they have been logged in ==
{{{#!highlight powershell
# This method looks like it should work, but LastLogon is stored at each domain controller, and the domain controller you are 
# using, may not have ever been logged into by the user
#Get-ADUser -Filter * -SearchBase "dc=home,dc=scotnpatti,dc=com" -ResultPageSize 0 -Prop CN,samaccountname,lastLogonTimestamp | 
#     select CN, samaccountname,@{n="lastLogonDate";e={[datetime]::FromFileTime($_.LastLogonTimestamp)}} 

# INSTEAD USE THIS METHOD
Import-Module ActiveDirectory
function Get-LastComputerLogonEvents
{
    $ComputerList = New-Object System.Collections.ArrayList
    $dcs = Get-ADDomainController -Filter {Name -like "*"}
    Write-Output $dcs
    $computers = Get-AdComputer -Filter *
    $time = 0
    foreach($computer in $computers)
    {
        foreach($dc in $dcs)
        {
            $hostname = $dc.HostName
            $currentComputer = Get-ADComputer $computer.SamAccountName | Get-ADObject -Server $hostname -Properties lastLogon
            if($currentComputer.LastLogon -gt $time)
            {
                $time = $currentComputer.LastLogon
            }
        }
        
        $dt = [DateTime]::FromFileTime($time)
        $temp = New-Object System.Object
        $temp | Add-Member -MemberType NoteProperty -Name "SamAccountName" -Value $computer.SamAccountName
        $temp | Add-Member -MemberType NoteProperty -Name "LastLogon" -Value $dt
        $ComputerList.Add($temp) | Out-Null
        $time = 0
    }
    return $ComputerList
}
$myList = Get-LastComputerLogonEvents | Sort-Object LastLogon | FT SamAccountName, LastLogon
Write-Output $myList
}}}

You can also try this one-liner

{{{#!highlight powershell
Get-ADUser -filter {enabled -eq $true} -SearchBase "ou=OU_Students,dc=cs,dc=southern,dc=edu" -Properties * | 
  Select-Object SamAccountName,Name,@{N='LastLogon';E={[DateTime]::FromFileTime($_.LastLogon)}}| 
  ? {$_.LastLogon -lt '2022-01-01'} | 
  Sort-Object LastLogon -Descending 
}}}

== Adding DNS records to Windows DNS - For CPTR 446 class ==

{{{#!highlight powershell
Import-Csv googleips.csv | ForEach-Object {
    Add-DnsServerResourceRecordA -Name $_.DNSName -ComputerName dc1.cs.southern.edu  -ZoneName cs.southern.edu $_.IP
}
}}}

== Setting up a Group Managed Service Account ==

An account that is automatically managed (e.g. password updates) by the domain. See get-help New-AdServiceAccount

{{{#!highlight powershell
# Adds the required root key to the key distribution service
Add-KdsRootKey -EffectiveTime ((get-date).AddHours(-10))
#Create an account:
New-ADServiceAccount Sql-Srv-Acct -DNSHostName Sql-Srv-Acct.home.scotpatti.com -PrincipalsAllowedToRetrieveManagedPassword "Domain Controllers"
#Install account on rita.home.scotnpatti.com
Install-ADServiceAccount -Identity 'Sql-Srv-Acct'
}}}

== Setting up a Storage Pool & Virtual Disk ==

{{{#!highlight powershell
$PhysicalDisk=(Get-PhysicalDisk -CanPool $True)
New-StoragePool -FriendlyName Carribean -StorageSubSystemFriendlyName "Windows Storage*" -ResiliencySettingNameDefault Parity -ProvisioningTypeDefault Thin -PhysicalDisks $PhysicalDisks -Verbose
New-VirtualDisk -StoragePoolFriendlyName Carribean -FriendlyName StarFish -ResiliencySettingName Parity -Size 2GB
Get-VirtualDisk -FriendlyName StarFish | Initialize-Disk -PartitionStyle GPT -PassThru
Get-Disk #will list the number of the StarFish disk if you don't see it from the command above
#If the disk is offline 
Set-Disk -Number [X] -IsOffline $False
Initialize-Disk -Number [X] -PartitionStyle GPT
New-Partition -DiskNumber [X] -DriveLetter '[Y]' -UseMaximumSize
Format-Volume -DriveLetter '[Y]' -FileSystem NTFS
}}}


= SCVMM Powershell scripts =


I needed this once when I was trying to refresh the Library share. It failed on refresh with an error saying that a DVD was in use and wouldn't refresh until it was no longer in use. The following commands allowed me to identify the machines. 

In general all of these need: 

{{{#!highlight powershell 
Import-Module VirtualMachineManager
}}}

== Get a list of Virtual Machines that have a DVD attached ==

{{{#!highlight powershell
Get-SCVMMServer -ComputerName Samuel
Get-SCVirtualMachine | Get-SCVirtualDVDDrive | Where-Object {$_.Connection -eq "ISOImage"} | Select Name, Connection, ISO
}}}

== List VMs at the end of the semester to be deleted ==

{{{#!highlight powershell
Get-SCVirtualMachine | Select Name, MarkedAsTemplate, Owner | Sort-Object -Property Owner, Name | Export-Csv -Path .\vms2019w.csv
}}}

== Get a list of VM Mac Addresses for CPTR 427 ==

{{{#!highlight powershell
Get-SCVirtualMachine | Where-Object { $_.Name -like "*427*" } | select -ExpandProperty VirtualNetworkAdapters | select MacAddress
}}}

== Add DHCP Reservations to Ruth ==

{{{#!highlight powershell
Add-DhcpServerv4Reservation -ScopeId 10.10.4.0 -IPAddress 10.10.4.10 -ClientId "00-1D-D8-C0-00-01" -ComputerName "ruth" -Description "00-1D-D8-C0-00-01"
}}}

== Get a list of IP address for SCVMM ==

{{{#!highlight powershell
Get-SCMACAddress -Assigned | Format-Table -Property `
@{label="MAC address"; expression={$_.Name};                  width=18},
@{label="Name";        expression={$_.Description};           width=30},
@{label="IP address";  expression={$a = $_.Address -replace ":", "";
                                   $l = Get-DhcpServerv4Lease -ScopeId 10.10.4.0 -ComputerName "ruth" -ClientId $a;
                                   $l.IPAddress};             width=16}

#Get-DhcpServerv4Lease -ScopeId 216.249.119.0 -ComputerName 'csdc01' -ClientId '001DD8B71C28'
}}}

== List SCVMM VMs/Templates and their Ownership - Change Ownership ==
{{{#!highlight powershell
Get-SCVMTemplate | ? { $_.Owner -eq "DOMAIN\X" } | Set-SCVMTemplate -Owner "DOMAIN\Y"
Get-SCVirtualMachine | ? { $_.Owner -eq "DOMAIN\X" } | Set-SCVirtualMachine -Owner "X\Y"
}}}

== List SCVMM VMs/Templates LimitCPUForMigration and Set to allow migration ==

Note: Setting LimitCPUForMigration = $true means that we are limiting the CPU so that it can migrate to different versions of the same CPU.

{{{#!highlight powershell
Get-SCVMTemplate | ? { $_.LimitCPUForMigration -eq $false } | Set-SCVMTemplate -LimitCPUForMigration $true
Get-SCVirtualMachine | ? { $_.LimitCPUForMigration -eq $false } | Set-SCVirtualMachine -LimitCPUForMigration $true
}}}

== List SCVMM VMs that are not associated with the cloud and associate them ==

{{{#!highlight powershell
$Cloud = $Cloud = Get-SCCloud -VMMServer samuel | ? {$_.Name -eq "Nimbus"}
Get-SCVirtualMachine -VMMServer samuel | ? {  $_.Cloud -ne $Cloud  } | Set-SCVirtualMachine -Cloud $Cloud
}}}

== Setting up a Windows 2019 Server for the first time ==

 1. Install the server - follow prompts.
 1. Setup the AVMA key as shown below OR use sconfig in the next step.

{{{#!highlight powershell
# Install the AVMA key.
slmgr /ipk TNK62-RXVTB-4P47B-2D623-4GF74

 1. 

#First run sconfig and setup the name, timezone and network, remote management and remote desktop. You can also setup windows update from here. 

# Next we need to install Windows update and get it started.
# This will install nuget package too.
Install-Module PSWindowsUpdate

# Now start the update process
#   First we'll look at what updates are there
Get-WUInstall 
#   Now install them
Install-WindowsUpdate
}}}

See the NAT setup near the bottom! That appears to have negated the need to change firewall rules. Also, I was not able to connect to the system via Server Manager right away. But a few minutes later, I could. No changes were made. But for posterity, they are here:

{{{#!highlight powershell
# To turn on or off the firewall 
Get-NetFirewallProfile
# to set firewall on or off
Set-NetFirewallProfile -Name Domain,Public,Private -Enabled True

#Te get/set the firewall rule for private networks to allow any machine on a private network.
Get-NetFirewallRule | ? {$_.DisplayGroup -like "Windows Remote Management*" -and $_.Profile -like "*Private*"} | Get-NetFirewallAddressFilter #Shows the address filter
Get-NetFirewallRule | ? {$_.DisplayGroup -like "Windows Remote Management*" -and $_.Profile -like "*Private*"} | Set-NetFirewallRule -RemoteAddress 192.168.1.0/24
}}}

Using Server Manager, install AD DS 

== Power shell to list of VM hard drives sizes ==

{{{#!highlight powershell
$vms = Get-SCVirtualDiskDrive -all
foreach ($v in $vms)
{
    $d = $v | select -ExpandProperty VirtualHardDisk
    Write-Output "$($v.Name), $($d.Size)"
}
}}}

== List the amount of memory used by virtual machines ==

{{{#!highlight powershell
Get-SCVirtualMachine | ForEach-Object { $size += $_.Memory }
}}}

Resources:

 * [[https://gallery.technet.microsoft.com/scriptcenter/2d191bcd-3308-4edd-9de2-88dff796b0bc#content|Powershell and Windows Update]]

== Power Shell Scripts to create a NAT network (without DHCP) on Windows 10 ==

{{{#!highlight powershell
New-VMSwitch -SwitchName "CPTE230" -SwitchType Internal
Get-VMSwitch #just for show
Get-NetAdapter #get the ifIndex of your vEthernet adapter e.g. 67
New-NetIPAddress -IPAddress 192.168.1.1 -PrefixLength 24 -InterfaceIndex 67 #Using the network ifIndex found above, e.g. 67
New-NetNat -Name CPTE230NAT -InternalIPInterfaceAddressPrefix 192.168.1.0/24 #create the NAT 
}}}

== Power Shell Script to List Network Adapters on a VM ==

Note: When looking at the !VirtualNetworkAdapterType value, "Emulated" means that it is "legacy" network adapter and "Synthetic" means its a non-legacy adapter. 

{{{#!highlight powershell
Get-SCVirtualMachine | ? { $_.Name -like "*pfsense*" } | Get-SCVirtualNetworkAdapter
}}}

== List VLANs for all CPTR 427 Virtual Machines in System Center ==

{{{#!highlight powershell
Get-SCVirtualMachine | 
    ? { $_.Name -like "*427*" } | 
    SELECT Name,@{label="VlanID";expression={($_.VirtualNetworkAdapters).VlanID}} | 
    Sort-Object Name | Export-Csv -Path .\VlanData.csv
}}}

== List All disconnected Adapters ==

{{{#!highlight powershell
$vms = Get-SCVirtualMachine
foreach ($vm in $vms) {
    $adapters = Get-SCVirtualNetworkAdapter -VM $vm
    foreach ($adapter in $adapters) {
        if ($adapter.VMNetwork -eq $null -or $adapter.VMNetwork -eq "" ) {
            Write-Host $vm.Name "missing connection on'" $adapter.MACAddress "'"
        }
    }
}
}}}

== Revoke all MAC addresses Back to the Pool ==

This came up as a maintenance issue when we lost some VMs, but not the configurations

{{{#!highlight powershell
$HostGroup = Get-SCVMHostGroup | where { $_.Path -eq "All Hosts\Server2016" }
$MACAddressPool = Get-SCMACAddressPool -VMHostGroup $HostGroup
$MACAddress = Get-SCMACAddress -MACAddressPool $MACAddressPool[0] 
ForEach ($item in $MACAddress) {
    Revoke-SCMACAddress $item 
}
}}}

== Change all VMs to use Dynamic Memory and reduce memory usage ==

{{{#!highlight powershell
$list = Get-SCVirtualMachine | ? { ($_.Name -like "*427*") -and ($_.DynamicMemoryEnabled -eq $False) }
foreach ($vm in $list) {
    if ($vm.Status -ne "PowerOff") {Stop-SCVirtualMachine -VM $vm}
    Set-SCVirtualMachine -VM $vm -DynamicMemoryEnabled $True -MemoryMB 1024 -DynamicMemoryMinimumMB 1024 -DynamicMemoryMaximumMB 6144
}
}}}

= Grading Scripts =

These are here for preparing various assignments in classes for grading, or actually grading them.

== General Prep for CPTR 446 handins of the !CompanyEmployees solutions ==

{{{#!highlight powershell
 param ($path)

function Change-ConnectionString
{
    param ( $filepath )
    $success = $false
    foreach ($f in $filepath)
    {
        if (-not(Test-Path -Path $f -PathType Leaf)) 
        {
            Write-Host "  ERROR: settings file not found!"
            break
        }
        $c = Get-Content $f -Raw | ConvertFrom-Json
        if ($c.ConnectionStrings.sqlConnection) 
        {
            $c.ConnectionStrings.sqlConnection = "Server=localhost;Database=CompanyEmployee;User Id=sa;Password=ConstraintDB123;"
            $c | ConvertTo-Json -Depth 32 | Set-Content $f
            $success = $true
        }
        else 
        {
            Write-Host "  ERROR: settings file does not contain a 'sqlConnection' property!!!"
            break
        }
    }
    if ($success) 
    {
        Write-Host "  Settings file successfully change."
    }
    else 
    {
        Write-Host "  Error: Unable to successsfully update any appsettings.json!!!"
    }
}

function Find-FirstFolder 
{
    param ( $folder )
    $list = Get-ChildItem -Path $folder -Recurse -File -Filter "appsettings.json" | Resolve-Path | ? { -not ( ( $_.Path -match "ware" ) -or ( $_.Path -match "bin" ) ) }
    if ($list.Length -gt 1) 
    {
        Write-Host "  Warning: More than one appsettings.json file found!"
    }
    return $list
}

if (!$path) 
{
    $path = "."
}
$ScriptPath = $pwd
$FullPath = Resolve-Path -Path $path
cd $FullPath
$files = Get-ChildItem -Filter "*.zip" | select Name
foreach ($f in $files)
{
    $parts = $f.Name.Split(".")
    $outDir = ".\" + $parts[0].Split("_")[0].replace(' ','')
    Write-Host $outDir
    New-Item -Path $outDir -ItemType Directory | Out-Null
    Expand-Archive $f.Name -DestinationPath $outDir
    $settings = Find-FirstFolder -folder $outDir
    Change-ConnectionString -filepath $settings
}
cd $ScriptPath.ProviderPath
}}}