Pass Varibles read from file to invoke-command - powershell

I'm struggling to remotely recycle all IIS app pools with powershell with the word "Test" in the name, but ALSO exclude a couple of specific AppPools with Test in the name. I can do it locally with:
## List of Apppool Names to Exclude
$Exclusions = Get-Content "C:\temp\Recycle TEST app pools Exclusions.txt"
## Load IIS module:
Import-Module WebAdministration
## Restart app pools with test in the name
Get-ChildItem –Path IIS:\AppPools -Exclude $Exclusions | WHERE { $_.Name -like "*test*" } | restart-WebAppPool}
However I can't get it to exclude the app pools from the list when I use:
$server = 'SERVER01', 'SERVER02'
## List of Apppool Names to Exclude
$Exclusions = Get-Content "C:\temp\Recycle TEST app pools Exclusions.txt"
## Load IIS module:
Import-Module WebAdministration
## Restart app pools with test in the name
invoke-command -computername $server -ScriptBlock {Get-ChildItem –Path IIS:\AppPools -Exclude $args[0] | WHERE { $_.Name -like "*test*" } | restart-WebAppPool}} -ArgumentList $Exclusions
The file "C:\temp\Recycle TEST app pools Exclusions.txt" does exist on the remote computer , but also does it need to? Can the list be passed in to the Invoke-Command also if it can be got to work?
Thanks in advance

While passing arrays as a single parameter can be difficult, you can take advantage of it here because you only have one argument type anyway.
invoke-command -computername $server -ScriptBlock {Get-ChildItem –Path IIS:\AppPools -Exclude $args[0] | WHERE { $_.Name -like "*test*" } | restart-WebAppPool}} -ArgumentList $Exclusions
In this, you use $args[0], but this is equivalent to $Exclusions[0] because all items in the array have been passed as arguments.
But if they've all been passed as arguments... that's what $args is. So use it exactly as you used $Exclusions locally.
Invoke-Command `
-ComputerName $server `
-ArgumentList $Exclusions `
-ScriptBlock {
Get-ChildItem –Path "IIS:\AppPools" -Exclude $args |
Where-Object Name -like "*test*" |
Restart-WebAppPool
}

Related

Using Powershell Get-ItemProperty through all of AD computers object

I'm a complete newbie in Powershell (and programming as you may have guessed), I want to get the result of the following PS command for each of our AD computer object and print the result in a text file...but I'm completely lost. Does anyone have a lifeline I could hold on to?
Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" | Select-String -Pattern "mysoftwarename"
Thank you very much.
$ScriptBlock = {Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" | Select-String -Pattern "mysoftwarename"}
$Computers = (Get-ADComputers -filter * ).name
$Creds = (Get-Credential)
foreach ($Computer in $Computers)
{
"`n`n$Computer`n" >> .\file.txt # "`n" just emulates Enter key press
Invoke-Command -ComputerName $Computer -ScriptBlock $ScriptBlock -Credential $Creds >> .\file.txt
}
This will work fine if you have all your computers online and PS remoting configured properly. Otherwise, it will require modifications.

How to find PST files on remote computers using Powershell script

I need some help. I cant’t find what’s wrong with my PowerShell script.
The goal is quite simple. I have to find (.*pst)-files on the users profile on domain computers in the network. Location to search is “C:\Users\”.
List of the PC names where exported to listcomputer.txt. The trouble is the script run with no errors and no message at all.
$computers = Get-Content c:\temp\listcomputer.txt
$filePath = "C:\Users\"
foreach($computer in $computers)
{
if(Test-Connection -ComputerName $computer -Quiet)
{
Invoke-Command -ComputerName $computer -ScriptBlock
{Get-ChildItem -Path $filePath -Recurse -Include '*.pst, *.ost'} }}
First of all I’ve to check connectivity to hosts by Test-Connection cmdlet.
Separately each of the command run successfully. I've tried it.
For example: Test-Connection -ComputerName $computer
runs with “true” result and it’s OK.
Also
Invoke-Command -ComputerName $computer -ScriptBlock {Get-ChildItem -Path $filePath -Recurse -Include '*.pst'} The result is displayed data with information about files were find in folders.
But all together run with no visible result in the PowerShell console console view result
Regards!
.pst can be located anywhere, even other drives, or attached storage. You are only looking for C:\.
So maybe this refactor to hit all potential connected drives.:
Get-Content -Path 'c:\temp\listcomputer.txt' |
ForEach-Object {
if(Test-Connection -ComputerName $PSItem -Quiet)
{
Invoke-Command -ComputerName $PSItem -ScriptBlock {
(Get-CimInstance -ClassName Win32_LogicalDisk).DeviceID |
ForEach-Object {
If ($PSItem -eq 'C:')
{Get-ChildItem -Path "$PSItem\Users" -Recurse -Include '*.pst, *.ost'}
Else {Get-ChildItem -Path $PSItem -Recurse -Include '*.pst, *.ost'}
}
}
}
}

Run Powershell Script on Multiple Remote Computers

Good day.
I apologize if this seems like a repetitive question but I the researches I have done have gotten me more confused. I'm trying to run the following Powershell script to delete a folder on some computers:
$users = get-childitem c:\users
foreach ($user in $users)
{
$folder = "C:\Users\" + $user + "\AppData\Local\Microsoft\OneDrive"
Remove-Item $folder -Recurse -Force -ErrorAction silentlycontinue
}
The script seems to work. How can I use this script on a list of remote computers?
Thank you.
You can utilize the Invoke-Command cmdlet with the ComputerName parameter. Example:
Invoke-Command { $env:ComputerName } -ComputerName SOMEMACHINE
As pointed out by dugas, you can use Invoke-Command to perform remote script execution using the -ScriptBlock and -ComputerName parameters.
# Create script block using surrounding {}
$sb = {
$users = Get-Childitem C:\Users -Directory -Name
foreach ($user in $users) {
$folder = "C:\Users\" + $user + "\AppData\Local\Microsoft\OneDrive"
Remove-Item $folder -Recurse -Force -ErrorAction silentlycontinue
}
}
# Create array of computer names since -ComputerName accepts an array
$computers = 'computer1','computer2','computer3'
Invoke-Command -ComputerName $computers -ScriptBlock $sb
There are numerous ways to traverse the remote directories. Using Get-ChildItem with -Directory and -Name parameters will return just the folder names under C:\Users.
Instead of having headache with offline computers, inaccwessible computers, etc, if you are using Active Directory domain, ask SysAdmin to create a Run-Once Scheduled Task using Group Policy Preferences.

Powershell retrieving cert by Thumbprint as string versus string variable

I'm trying to piece together some PowerShell code to loop through a list of servers, return some info regarding their IIS sites and bindings, and if they have an https binding, get the certificateHash and use that locate the cert by thumbprint and return its expiration date.
The problem I am having is, when i run my code below $binding.cerficateHash seems to return what I would expect, a string of the cert Hash, but when I use that certificateHash property to try and get the cert by its thumbprint, it doesnt work... but when I take the raw string value of the certificateHash value and hardcode it, it works...
I've inspected the certificateHash.GetType() and it appears to be just a string, so i dont understand what im doing wrong, and ive tried a handful of things, with no avail, granted this is my first crack at powershell so there's lots I don't know.
$sites = Invoke-Command -ComputerName $serverName { Import-Module WebAdministration; Get-ChildItem -path IIS:\Sites } -ErrorAction SilentlyContinue
foreach($site in $sites)
{
$serverName
$site.name
$site.physicalPath
foreach($binding in $site.bindings.Collection)
{
$binding.protocol
$binding.bindingInformation
$binding.certificateHash
$binding.certificateStoreName
if($binding.certificateHash)
{
# This outputs AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
$binding.certificateHash
# this retrieves a cert and returns its expiration date, Woohooo!
Start-Job Invoke-Command -ComputerName $serverName -ScriptBlock { (Get-ChildItem -path Cert:\LocalMachine\WebHosting | Where-Object {$_.Thumbprint -eq "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" })[0].GetExpirationDateString() }
# this does not find a cert, and ive tried many things, and no dice.
Start-Job Invoke-Command -ComputerName $serverName -ScriptBlock { (Get-ChildItem -path Cert:\LocalMachine\WebHosting | Where-Object {$_.Thumbprint -eq $binding.certificateHash })[0].GetExpirationDateString() }
# i've tried extracting the hash via "tostring" and using that, no dice
$hash = $binding.certificateHash.ToString()
Start-Job Invoke-Command -ComputerName $serverName -ScriptBlock { (Get-ChildItem -path Cert:\LocalMachine\WebHosting | Where-Object {$_.Thumbprint -eq $hash })[0].GetExpirationDateString() }
# i've tried adding some wildcards and using the -like operator, no dice.
$hash = "*" + $binding.certificateHash + "*"
Start-Job Invoke-Command -ComputerName $serverName -ScriptBlock { (Get-ChildItem -path Cert:\LocalMachine\WebHosting | Where-Object {$_.Thumbprint -lilke $hash })[0].GetExpirationDateString() }
}
}
}
Example output for a site.
Site1
D:\Apps\site1
http
*:80:Site1-test.ourdomain.com
https
*:443:Site1-test.ourdomain.com
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
WebHosting
The computer you invoke the script block on doesn't know about the $binding variable in your local session. (That's also why it works when passing a literal string.)
Try passing the value as argument:
Invoke-Command -Computer $serverName -Script {
param ($hash)
(gci Cert:\LocalMachine\WebHosting | ? Thumbprint -eq $hash)[0].GetExpirationDateString()
} -Arg $binding.certificateHash

Stopping & Restarting Services Remotely Using Set-Service

I've got a list of 10-15 services that I routinely need to restart on 6 servers. I have a script that calls a list of services, then calls a list of the servers, and then stops all the services:
$Services = Get-Content -Path "C:\Powershell\Services.txt"
$Machines = Get-Content -Path "C:\Powershell\Machines.txt"
Get-Service -Name $Services -ComputerName $Machines | Set-Service -Status Stopped
I then have another separate script to start them up again:
$Services = Get-Content -Path "C:\Powershell\Services.txt"
$Machines = Get-Content -Path "C:\Powershell\Machines.txt"
Get-Service -Name $Services -ComputerName $Machines | Set-Service -Status Running
I've checked around and can't seem to find a way of putting this into a single script. As I understand, Set-Service only has the ability to Stop, Start & Pause services, not restart them at the same time.
Any ideas? I might be missing something completely obvious.
To restart services simply use Restart-Service:
$Services = Get-Content -Path "C:\Powershell\Services.txt"
$Machines = Get-Content -Path "C:\Powershell\Machines.txt"
Get-Service -Name $Services -ComputerName $Machines | Restart-Service
Since according to the comments PowerShell v6 has removed support for remote access from the *-Service cmdlets you need to resort to Invoke-Command for remote execution when running v6 or newer, like this:
Invoke-Command -Computer $Machines -ScriptBlock {
Get-Service -Name $using:Services -ErrorAction SilentlyContinue |
Restart-Service
}
or like this:
Invoke-Command -Computer $Machines -ScriptBlock {
Restart-Service $using:Services -ErrorAction SilentlyContinue
}
Another option would be WMI:
$fltr = ($Services | ForEach-Object { 'Name="{0}"' -f $_ }) -join ' or '
Get-WmiObject Win32_Service -Computer $Machines -Filter $fltr | ForEach-Object {
$_.StopService()
$_.StartService()
}
I am with Ansgar, this should work
$Services = Get-Content -Path "C:\Powershell\Services.txt"
$Machines = Get-Content -Path "C:\Powershell\Machines.txt"
foreach ($service in $services){
foreach ($computer in $Machines){
Invoke-Command -ComputerName $computer -ScriptBlock{
Restart-Service -DisplayName $service}
}
}
it is a little messy but should give you a starting point
Sorry I forgot to take time to explain what is going on, so you import each of your txt docs and then it will process for each service and each computer and restart the services.
You can try this single liner command:
Get-Content .\services.txt | %{Get-WmiObject -Class Win32_Service -ComputerName (Get-Content .\computers.txt) -Filter "Name='$_'"} | %{$_.StopService()}; Get-Content .\services.txt | %{Get-WmiObject -Class Win32_Service -ComputerName (Get-Content .\computers.txt) -Filter "Name='$_'"} | %{$_.StartService()}