Windows Powershell
ISE - PowerShell IDE
Untitled.ps1 - when working in ISEv2 or v4 in a script edit section, you can select code and press F8 to execute it
$_ - substitute a singular record in array
-eq, -or -and - dash means operator
Test network connection
Testing from PowerShell if NFS port on remote server is open. The test takes around 5 seconds, them prints output.
PS C:\> Test-NetConnection -ComputerName 10.1.20.1 -Port 2049 ComputerName : 10.1.20.1 RemoteAddress : 10.1.20.1 RemotePort : 2049 InterfaceAlias : Ethernet SourceAddress : 10.1.10.111 PingSucceeded : True PingReplyDetails (RTT) : 2 ms TcpTestSucceeded : True
PowerShell of linux commands
- Tail
PS1 C:\> Get-Content -Path "C:\scripts\test.log" -Wait -Tail 100 $ tail -f /mnt/c/scripts/test.log
- Curl
PS1 C:\> (Invoke-WebRequest -Headers @{"Host"="api.example.com"} -Uri http://127.0.0.1:8080 -UseBasicParsing).statuscode PS1 C:\> Invoke-RestMethod -Headers @{"Host"="api.example.com"} -Uri http://127.0.0.1/healthcheck $ curl --header 'Host: api.example.com' http://127.0.0.1/
- Wget
#Optional enable latest TLS, by default it uses TLS1.0, use 'Ssl3' in edge cases PS1 C:\> [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls" PS1 C:\> Invoke-WebRequest https://github.com/Example/package.zip -OutFile package.zip $ wget https://github.com/Example/package.zip -OutFile package.zip
- Troubleshooting
- Error: The request was aborted: Could not create SSL/TLS secure channel. - set SecurityProtocol
Set a hostname
<syntaxhighlightjs lang="powershell">
- ideally this should be up to 15 chars long to fit NetBios name otherwise it will be truncated
Rename-Computer -NewName server-1-eu -restart </syntaxhighlightjs>
Windows features
List installed features
<syntaxhighlightjs lang="powershell"> PS C:> DISM /online /get-features /format:table Deployment Image Servicing and Management tool Version: 6.3.9600.17031 Image Version: 6.3.9600.17031 Features listing for package : Microsoft-Windows-ServerCore-Package~aaaaaaaaaae35~amd64~~6.3.9600.16384
| --------
Feature Name | State
| --------
NetFx4ServerFeatures | Enabled NetFx4Extended-ASPNET45 | Enabled </syntaxhighlightjs>
Install Windows feature
nfs-client
<syntaxhighlightjs lang="powershell"> PS C:\> Get-WindowsFeature *nfs* Display Name Name Install State
---- -------------
[ ] Server for NFS FS-NFS-Service Available [ ] Client for NFS NFS-Client Available [ ] Services for Network File System Man... RSAT-NFS-Admin Available
PS C:\> Install-WindowsFeature NFS-Client -IncludeAllSubFeature -IncludeManagementTools Success Restart Needed Exit Code Feature Result
-------------- --------- --------------
True No Success {Client for NFS} </syntaxhighlightjs>
Other features, confirmed Windows Server Base 2019 | AWS
<syntaxhighlightjs lang="powershell">
Install-WindowsFeature -name Web-Server -IncludeManagementTools #IIS
</syntaxhighlightjs>
Install Hyper-V feature
Verified: Windows 10 Pro
Optional: Setup the Disk to allow the hypervisor <syntaxhighlightjs lang="powershell">
- BCDEDIT /Set `{current`} hypervisorlaunchtype auto
</syntaxhighlightjs>
Install Hyper-V feature
<syntaxhighlightjs lang="powershell">
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All #PS1
DISM /Online /Enable-Feature /All /FeatureName:Microsoft-Hyper-V #CMD
</syntaxhighlightjs>
Restart is required
- Allow Hyper-V and VirtualBox to coexist
Hyper-V is enabled during boot process, so creating a additional BCDEDIT entry will be the solution. Open PS in Admin mode, and run as follows: <syntaxhighlightjs lang="powershell"> C:>bcdedit /copy {current} /d "Windows 10 - No hypervisor" The entry was successfully copied to {ade52f12-1207-11e9-ad93-f3c1556fc814}. C:>bcdedit /set {ade52f12-1207-11e9-ad93-f3c1556fc814} hypervisorlaunchtype off #use guid from the previous command output The operation completed successfully. </syntaxhighlightjs> In order to access the new boot menu:
- restart and hold down
shift
on the keyboard while clicking Restart with the mouse - on a boot menu select Use another operating system > Windows 10 - No hypervisor
Download a file
Bits transfer
Windows has background service to download files. The admin console is called bitsadmin
where equivalent Powershell cmdlets are *-BitsTransfer
$tmpPath="C:\tmp" If (-Not (Test-Path $tmpPath -pathType container)) { md $tmpPath } $tentacle_url="https://octopus.com/downloads/latest/WindowsX64/OctopusTentacle" $tentacle_file="tentacle_install.msi" Start-BitsTransfer -Source $tentacle_url -Destination $tmpPath\$tentacle_file WriteOutput "BitsTransfer - success: $?"
The important downside is that you cannot use BitsTransfer with:
- schedule job unless you tick "Run when Logged in"
- AWS Windows user_data scripts
This is by design it requires interactive session. From docs "BITS transfers files only when the job owner is logged on and a network connection (LAN or modem) is established. BITS processes the transfer job using the security context of the job owner. The user who created the job is considered the owner of the job. However, a user with administrator privileges can take ownership of another user's job."
System.Net.WebClient
A common .NET class used for downloading files is the System.Net.WebClient class.
$WebClient = New-Object System.Net.WebClient $WebClient.DownloadFile("http://mirror.filearena.net/pub/speed/SpeedTest_128MB.dat","C:\tmp\file.zip") #Or one-liner $url="http://mirror.filearena.net/pub/speed/SpeedTest_128MB.dat" $file="C:\tmp\file.zip" (New-Object System.Net.WebClient).DownloadFile($url, $file)
Install an application
This is usually done using msiexec
it will start installing a software in background. To have better control of it, eg. running configuration task for this software straight after installation. You can use cmd start
or Powershell cmdlet Start-Process
with -Wait
option. It will start separate process (for eg. software installation) and wait until completed.
$tmpPath="C:\tmp" $splunk_forwarder_file="" Start-Process msiexec.exe -ArgumentList "/i $tmpPath\$splunk_forwarder_file RECEIVING_INDEXER=splunk.acme.com:9997 DEPLOYMENT_SERVER=splunk.acme.com:8089 AGREETOLICENSE=Yes", "/quiet" -Wait #Without -wait, following commands fail as Splunk Forwarder would not be fully installed C:\"Program Files"\SplunkUniversalForwarder\bin\splunk set servername ${tf_hostname} -auth admin:changeme C:\"Program Files"\SplunkUniversalForwarder\bin\splunk set default-hostname ${tf_hostname} -auth admin:changeme
Please pay attention to a way how arguments to application msiexec.exe
have been passed in "/i app.exe apparg1 apparg2", "/quiet"
References
Modules
Load ActiveDirectory module to have access to AD, pre-requirement to execute most commands below
Import-Module -Name ActiveDirectory
Create a big file
fsutil file createnew big1k 1024 # 1Kb, filled in with Null fsutil file createnew big1g 1073741824 # 1Gb
Schedule task
Create a schedule task that runs on a powershell script on boot, then disables itself.
$schAction = New-ScheduledTaskAction ` -Execute "Powershell.exe" ` -WorkingDirectory C:\ProgramData\Amazon\EC2-Windows\Launch\Scripts ` -Argument '-NoProfile -WindowStyle Hidden -NoLogo -NonInteractive -c "powershell .\TentacleRegister.ps1 -verbose >> .\TentacleRegisterScheduleTask.log 2>&1"' $schTrigger = New-ScheduledTaskTrigger -AtStartup $schPrincipal = New-ScheduledTaskPrincipal -UserId "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest Register-ScheduledTask -Action $schAction -Trigger $schTrigger -TaskName "RegisterTentacle" -Description "Register OctopusDeploy" -Principal $schPrincipal #Create .ps1 script $TentacleRegisterFileContent = @' $TentaclePath="C:\Program Files\Octopus Deploy\Tentacle" if (-Not (Test-Path $TentaclePath -pathType container)) { Write-Output "Octopus path not found"; exit 1 } cd $TentaclePath .\Tentacle.exe create-instance --instance $env:computername --config "C:\Octopus\Tentacle.config" --console .\Tentacle.exe new-certificate --instance $env:computername --if-blank --console .\Tentacle.exe configure --instance $env:computername --reset-trust --console .\Tentacle.exe configure --instance $env:computername --home "C:\Octopus" --app "C:\Octopus\Applications" --port "10933" --console .\Tentacle.exe configure --instance $env:computername --trust ${tf_octopus_fingerprint} --console netsh advfirewall firewall add rule "name=Octopus Deploy Tentacle" dir=in action=allow protocol=TCP localport=10933 $localIP=(Invoke-RestMethod http://169.254.169.254/latest/meta-data/local-ipv4) .\Tentacle.exe register-with --instance $env:computername ` --server "https://deploy.contactengine.net" --apiKey="${tf_octopus_token}" ` --role "microservices" --environment "${tf_octopus_environment}" ` --comms-style TentaclePassive -h $localIP --force --console .\Tentacle.exe service --instance $env:computername --install --stop --start --console #Disable/delete scheduled task #Unregister-ScheduledTask -TaskName "RegisterTentacle" -Confirm:$false Disable-ScheduledTask -TaskName "RegisterTentacle" '@
What is worth to note re-direction -Argument '-NoProfile -WindowStyle Hidden -NoLogo -NonInteractive -c "powershell .\TentacleRegister.ps1 -verbose >> .\TentacleRegisterScheduleTask.log 2>&1"'
that allows to log execution STD and STDERR to a file. Please note that most of the schedule task scripts run in SYSTEM user context. Then it's also important that the task name match here RegisterTentacle
Extract from Active Directory
<syntaxhighlightjs lang="powershell"> get-aduser -Filter {Samaccountname -eq "Smith"} -properties Organization get-aduser -Filter {(Givenname -eq "Smithy") -and (Surname -eq "Smith")}
- Build array $users with all Samaccountname(loginnames) with additional properties: Name, Description
$users = get-aduser -Filter {Samaccountname -like "*"} -properties Name, Description
- Return array object count
$users.count
- Search array $users where $_ each object in array field samaccountname has a given string
$users | Where-Object {$_.samaccountname -eq "string_to_compare"}
- Build array of enabled and disabled accounts in AD where field Enabled equal $true ($true boolean is 1 $false is 0)
$enabledusers = $users | Where-Object {$_.Enabled -eq $true } $disabledusers = $users | Where-Object {$_.Enabled -eq $false}
- Filter array $disabledusers returning only Samaccountname, GivenName, Surname and display (ft = Format-table)
$disabledusers | Select-Object Samaccountname, GivenName, Surname | ft -AutoSize
- Build create new array from filter of $users array if name or description contains a string
$aausers = $users | Where-Object {( $_.Name -like "*aa*") -or ($_.Description -like "*bb*")} $aausers | Select-Object Samaccountname, GivenName, Surname, Enabled | Sort-Object Enabled | ft -AutoSize
- Print a table with records matching $aauser if another AD account has the same name and surname
foreach ($aauser in $aausers) {
$realuser = [array](get-aduser -Filter {((Givenname -eq $aauser.Givenname) -and (Surname -eq $aauser.Surname))}) write-host $aauser.samaccountname "|" $aauser.name "|" $aauser.enabled "|"$realuser[0].SamAccountname "|"$realuser[0].GivenName"|" $realuser[0].Surname"|" $realuser[0].Enabled
}
- Build array with GivenName, Surname that match filter of: Enabled field is false (disabled account)
$temp = Get-ADUser -Properties GivenName, Surname -filter {Enabled -eq $false}
- Export the array to CSV file
$temp | Export-Csv temp.csv </syntaxhighlightjs>
AD Extract 2
$reportdate = Get-Date -Format yyyyMMdd-HHmm $csvreportfile = "ADUsers-extract-$reportdate.csv" Get-ADUser -SearchBase "OU=Users,DC=corp,DC=local" -Filter * -ResultSetSize 5000 | Get-ADUser -Properties * | select SamAccountName,EmailAddress,Givenname,Surname,Title,Department,Enabled | Export-Csv -Path $csvreportfile -NoTypeInformation
Create users from csv
Csv file BulkAddADUsers.csv
Name,GivenName,Surname,SamAccountName,UserPrincipalName,EmailAddress,AccountEnabled,AccountPassword,PasswordNeverExpires,Path Full Name,Firstname,Surname,fsurname,fsurname@example.com,fsurname@example.com,$true,PassWord123,$true,"OU=Users,OU=Testing ,OU=USA,DC=corp-example,DC=io"
BulkAddADUsers.ps1 <syntaxhighlightjs lang="powershell">
- CSV headline: Name,GivenName,Surname,SamAccountName,UserPrincipalName,EmailAddress,Enabled,AccountPassword,PasswordNeverExpires,Path
- Script - CSV headline
- Name - first+last name
- GivenName - first name
- Surname - last name
- SamAccountName - username
- UserPrincipalName - it is user-logon-name, where you need to choose domain, eg. test@example.com or @corp-example.io
- Path - object location, use get-aduser <SamAccountName>
Import-Csv .\BulkAddADUsers.csv | % { ` New-ADUser -Name $_.Name -GivenName $_.GivenName -Surname $_.Surname -SamAccountName $_.SamAccountName `
-UserPrincipalName $_.UserPrincipalName -EmailAddress $_.EmailAddress ` -Enabled $true -AccountPassword (ConvertTo-SecureString $_.AccountPassword -AsPlainText -force) ` -PasswordNeverExpires $true -Path $_.Path
}
- errors
- -Enabled cannot read $true value from CSV therefore it has been hard coded
</syntaxhighlightjs>
Get membership of a user
Get-ADPrincipalGroupMembership username| select name
IIS - create a website
Tested on Server 2012 R2 Data Centre in Azure <syntaxhighlightjs lang="powershell"> $SiteName = "WWW" $AppPoolName = "WWWAppPool" $SiteFolder = Join-Path -Path 'C:\inetpub\wwwroot' -ChildPath $SiteName $LogDir = "d:\Logs\iis_logs\$SiteName" $HostHeader = "www.example.com"
Import-Module WebAdministration
- create appPool
if(-Not (Test-Path IIS:\AppPools\$AppPoolName)) { New-WebAppPool -Name $AppPoolName -Force }
- create Site
if(-Not (Test-Path $SiteFolder -pathType container)) { md $SiteFolder } New-WebSite -Name $SiteName -PhysicalPath $SiteFolder -Force -ApplicationPool $AppPoolName Get-WebBinding -Name $SiteName -Port 80 | Remove-WebBinding New-WebBinding -Name $SiteName -Protocol http -Port 80 -IPAddress * -HostHeader $HostHeader New-WebBinding -Name $SiteName -Protocol http -Port 8080 -IPAddress * -HostHeader $HostHeader
- Logging dir
if (-Not (Test-Path $LogDir -pathType container)) { md $LogDir } Set-ItemProperty "IIS:\Sites\$SiteName" -name logFile.directory -value $LogDir Start-WebSite -Name $SiteName </syntaxhighlightjs>
File content
<syntaxhighlightjs lang="powershell"> $hostsFileContent = @" 127.0.0.1 example.com 127.0.0.1 example.local "@
Add-Content -Path "c:\Windows\System32\drivers\etc\hosts" -Value $hostsFileContent Set-Content -Path "c:\Windows\System32\drivers\etc\hosts" -Value $hostsFileContent </syntaxhighlightjs>