Uninstall program on several servers - list

I have a bunch of servers I have to uninstall an app from. I am using:
$app = Get-WmiObject -Class Win32_Product | Where-Object {
$_.Name -match "application name"
}
$app.Uninstall()
I have tested the above out and it works great. I want to now run this so it uninstalls the app on a bunch of servers. I know I can use the for each option but for some reason I am having an issue getting it to work.
I created a text file called servers and listed my servers in there but it errors out each time.
Does anyone have a good pay to add a for each part to my above uninstall portion so it works?

The -ComputerName parameter of Get-WmiObject accepts a list of computernames.
$servers = Get-Content 'C:\your\computerlist.txt'
Get-WmiObject -Computer $servers -Class Win32_Product |
? { $_.Name -like '*application name*' } |
% { $_.Uninstall() }

Later on the page that you got your original code from, there is an answer from David Setler that does what you need. Slightly modified to fir your scenario:
$computers = Get-Content C:\servers.txt
foreach($server in $computers){
$app = Get-WmiObject -Class Win32_Product -computer $server | Where-Object {
$_.Name -match "application name"
}
$app.Uninstall()
}
Assuming $computers is the list of servers from your servers text file.

I would stay away from win32_product because this class isn't working properly.
See https://support.microsoft.com/en-us/kb/974524.
Basicly what happens when you query this class is that every msi will trigger a repair an the software package (spamming the eventlog) which in some cases can screw with installed software (I've seen broken installations of some programs after querying this class - though it's rare, you don't want to risk this on production servers).

Related

How can I retrieve all data from a given AWS Powershell cmdlets/alias?

When running a cmdlet like Get-WKSWorkspaces, it will return a set of properties about your workspaces (e.g. WorkspaceID, Username, SubnetID, BundleID, etc.), but not everything you see in the AWS GUI. I am specifically trying to pull things like Running Mode, Compute Type, and Creation Time as well, but can't seem to find where to pull it.
In my research, I got up to the point where I was using $AWSHistory to try and dig deeper into the data returned from my previous cmdlets, but have definitely hit a wall and can't seem to get around it.
I do have a partial command that is giving me most of the output I need:
$region = Get-DefaultAWSRegion
$lastuserconnect = Get-WKSWorkspacesConnectionStatus | Select LastKnownUserConnectionTimestamp
Get-WKSWorkspace -ProfileName ITSLayer1-053082227562-Profile | Select WorkspaceID, UserName, BundleID, DirectoryID,
#{Name="Region"; Expression={$region.Region}},
#{Name="LastKnownUserConnect"; Expression=
{$lastuserconnect.LastKnownUserConnectionTimestamp}}
Update for posterity: Actually got something decent to come out here. It's slow, but it renders in a table format pretty well and includes a bit at the start to select your AWS region.
Suggestions for improvement include:
Automatically switching the Region select to get all workspaces from
the main Regions we use
Cleaning the lines up so it's easier to
read
Getting the region to automatically append the filename so it
doesn't overwrite your file every time (it's in there but broken at
the moment...still pops out a file with 'workspace_properties.csv'
as the name)
Optimizing the script because it's pretty slow
$lastuserconnect = Get-WKSWorkspacesConnectionStatus -ProfileName $profile
$defaultregion = Get-DefaultAWSRegion
$showallregions = Get-AWSRegion
$exportpath = "" + $env:USERPROFILE + "\workspace_properties" +
$defaultregion.Region + ".csv"
$showallregions | Format-Table
$setregion = Read-Host -Prompt 'AWS Region'
Clear-DefaultAWSRegion
Set-DefaultAWSRegion $setregion
Get-WKSWorkspace -ProfileName $profile | Select WorkspaceID, UserName, BundleID, DirectoryID, #{Name="ComputeType"; Expression={$.WorkspaceProperties.ComputeTypeName}}, #{Name="RunningMode"; Expression={$.WorkspaceProperties.RunningMode}}, #{Name="Region"; Expression={$defaultregion.Region}}, #{Name="LastKnownUserConnect"; Expression={$_ | foreach {$lastuserconnect = Get-WKSWorkspacesConnectionStatus -ProfileName $profile -WorkspaceId $_.WorkspaceId; echo $lastuserconnect.LastKnownUserConnectionTimestamp}}} | Export-Csv $exportpath
Here is an example of fetching those properties you are looking for:
Get-WKSWorkspace | foreach {
$connectionStatus = Get-WKSWorkspacesConnectionStatus -WorkspaceId $_.WorkspaceId;
echo "";
echo "==> About $($_.WorkspaceId)";
echo "Last State Check: $($connectionStatus.ConnectionStateCheckTimestamp)";
echo "User Last Active: $($connectionStatus.LastKnownUserConnectionTimestamp)";
echo "Directory: $($_.DirectoryId)";
echo "Compute: $($_.WorkspaceProperties.ComputeTypeName)";
echo "Running mode $($_.WorkspaceProperties.RunningMode)";
echo "State $($_.State)"
}
I don't see a 'Creation Time' on workspace on the console either.
[edit]
I believe you are looking for a way to export these info, may be below code will help:
[System.Collections.ArrayList]$output=#()
Get-WKSWorkspace | foreach {
$connectionStatus = Get-WKSWorkspacesConnectionStatus -WorkspaceId $_.WorkspaceId;
$bunch = [pscustomobject]#{
WorkspaceId = $_.WorkspaceId
LastStateCheck=$connectionStatus.ConnectionStateCheckTimestamp
UserLastActive=$connectionStatus.LastKnownUserConnectionTimestamp
Directory= $_.DirectoryId
Compute=$_.WorkspaceProperties.ComputeTypeName
Runningmode= $_.WorkspaceProperties.RunningMode
State= $_.State
}
$output.Add($bunch)|Out-Null
}
$output | Export-Csv -NoType c:\dd.csv
From looking at the docs it appears what you are looking for in the property WorkspaceProperties which contains an Amazon.WorkSpaces.Model.WorkspaceProperties object with the following properties:
ComputeTypeName Amazon.WorkSpaces.Compute
RootVolumeSizeGib System.Int32
RunningMode Amazon.WorkSpaces.RunningMode
RunningModeAutoStopTimeoutInMinutes System.Int32
UserVolumeSizeGib System.Int32
Not sure about the CreationTime though...

Pull Server names and ip address and see if they're live

I am looking to run a PowerShell script that will pull all servers from AD, show me the FQDN and IP address as well as tell me if the server is pinging.
I have a couple of scripts that do certain parts but would like to get something all in one and am having a hard time doing it.
Ping a list of servers:
$ServerName = Get-Content "c:\temp\servers.txt"
foreach ($Server in $ServerName) {
if (test-Connection -ComputerName $Server -Count 2 -Quiet ) {
"$Server is Pinging "
} else {
"$Server not pinging"
}
}
I also have a script to pull all servers from AD which shows server name, FQDN, and OS version:
Import-Module ActiveDirectory
Get-ADComputer -Filter {OperatingSystem -like '*Windows Server*'} -Properties * |
select Name, DNSHostName, OperatingSystem
Any help in getting a script to show me all servers in my environment with FQDN, IP address and if there live would be appreciated.
You should only choose desired properties with the -Property argument and not pull everything through network with *. Also quotes should be used with -Filter, not braces.
You can add a calculated property to Select-Object and get the value from Test-NetConnection:
Get-ADComputer -Filter "OperatingSystem -like '*Windows Server*'" -Properties dnshostname, operatingsystem |
Select-Object name, dnshostname, operatingsystem, `
#{n="PingSucceeded";e={(Test-NetConnection $_.name).PingSucceeded}}

Powershell script to get only Hour and Minute from NET TIME command

I am trying to retrieve only the Date and Time from the PowerShell script, Below is what I have tried till now:
Script:
NET TIME \\ComputerName | Out-File $location
(Get-Content $location) | % {
if ($_ -match "2018 : (.*)") {
$name = $matches[1]
echo $name
}
}
net time output is as below:
Current time at \\Computer Name is 1/3/2018 1:05:51 PM
Local time (GMT-07:00) at \\Computer Name is 1/3/2018 11:05:51 AM
The command completed successfully.
I only need the part in local time "11:05".
Although Get-Date doesn't support querying remote computers, the date/time and timezone information from a remote computer can be retrieved using WMI; an example can be found at this TechNet PowerShell Gallery page. Using the Win32_LocalTime class, adjusted based on the Win32_TimeZone class, will provide the information in a form that is easily converted into a [DateTime] for further use in your script.
Use -match to test a regex
Then check the matches with autogenerated $matches array
PS> "Current time at \Computer Name is 1/3/2018 1:05:51 PM Local time (GMT-07:00) at \Computer Name is 1/3/2018 11:05:51 AM" -match '(\d\d:\d\d):'
True
PS> $matches
Name Value
---- -----
1 11:05
0 11:05:
PS> $matches[1]
11:05
Brief
You can use this function to get whatever information you want. I adapted the code from this script. It converts the LocalDateTime value obtained using Get-WmiObject into a DateTime object. You can do whatever you want with the date information thereafter. You can also adapt this to use whichever DateTime variable you want (i.e. last boot time).
Code
function Get-RemoteDate {
[CmdletBinding()]
param(
[Parameter(
Mandatory=$True,
ValueFromPipeLine=$True,
ValueFromPipeLineByPropertyName=$True,
HelpMessage="ComputerName or IP Address to query via WMI"
)]
[string[]]$ComputerName
)
foreach($computer in $ComputerName) {
$timeZone=Get-WmiObject -Class win32_timezone -ComputerName $computer
$localTime=([wmi]"").ConvertToDateTime((Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computer).LocalDateTime)
$output=[pscustomobject][ordered]#{
'ComputerName'=$computer;
'TimeZone'=$timeZone.Caption;
'Year'=$localTime.Year;
'Month'=$localTime.Month;
'Day'=$localTime.Day;
'Hour'=$localTime.Hour;
'Minute'=$localTime.Minute;
'Seconds'=$localTime.Second;
}
Write-Output $output
}
}
Call the function using either of the following methods. The first is for a single computer and the second for multiple computers.
Get-RemoteDate "ComputerName"
Get-RemoteDate #("ComputerName1", "ComputerName2")
I realize this may not work for you if you do not have PowerShell remoting enabled, but if it is I would do it this way.
Invoke-Command -ComputerName ComputerName -ScriptBlock {(Get-Date).ToShortTimeString()}

Why Am I Seeing These Errors in My SSRS Powershell Script in One Environment but Not Another?

I have a Powershell Script I'm working on for post-migration SSRS report administration tasks.
In this particular scenario we have a DEV environment (where I've been primarily testing) which hosts a single instance of SSRS, and a Prod environment which is a scaled out deployment across 4 nodes.
I'm new to Powershell (just discovered it 2 days ago...) and the script I have is pretty simple:
Clear-Host 
$Username = "domain\myUsername"
$Password = "myPassword"
$Cred = New-Object System.Management.Automation.PSCredential -ArgumentList #($Username,(ConvertTo-SecureString -String $Password -AsPlainText -Force))
# Dev Connection String
$webServiceUrl = 'http://DEVwebServer.domain.com/reportserver/reportservice2010.asmx?WSDL'
# Prod Connection String
# $webServiceUrl = 'http://PRODwebServerNode1.domain.com/reportserver/reportservice2010.asmx?WSDL'
$rs = New-WebServiceProxy -Uri $webServiceUrl -Credential $Cred
 
$reports = $rs.ListChildren("/Some Folder Under Root", $true) | Where-Object { $_.TypeName -eq "Report" }
$type = $ssrsProxy.GetType().Namespace;
$schedDefType = "{0}.ScheduleDefinition" -f $type;
$schedDef = New-Object ($schedDefType)
$warning = #();
foreach ($report in $reports) {
$sched = $rs.GetExecutionOptions($report.Path, [ref]$schedDef);
$snapShotExists = $rs.ListItemHistory($report.Path);
if($sched -eq "Snapshot") {
Write-Host "Following report is configured to run from Snapshot:" -ForegroundColor Yellow
Write-Host ("Report Name: {0}`nReport Path: {1}`nExecution Type: {2}`n" -f $report.Name, $report.Path, $sched)
if ($snapShotExists) {
Write-Host "Does Snapshot Exist..?`n" -ForegroundColor Yellow
Write-Host "Yes!`tNumber of Snapshots: " $snapShotExists.Count -ForegroundColor Green
$snapShotExists.CreationDate
Write-Host "`n------------------------------------------------------------"
}
elseif (!$snapShotExists) {
Write-Host "Does Snapshot Exist..?`n" -ForegroundColor Yellow
Write-Host ("No!`n") -ForegroundColor Red
Write-Host "Creating Snapshot.......`n" -ForegroundColor Yellow
$rs.CreateItemHistorySnapshot($report.Path, [ref]$warning);
Write-Host "Snapshot Created!`n" -ForegroundColor Green
$snapShotExists.CreationDate
Write-Host "`n------------------------------------------------------------"
}
}
}
The purpose of the script is simply to recursively iterate over all of the reports for the given folder in the $reports variable, check to see if the execution type is set to "Snapshot", if it is check to see if a "History Snapshot" exists, and if one does not exist, create one.
When I run this in Dev it works just fine, but when I run in PROD I get the following error repeated for each $report in my foreach loop:
Any ideas on why this would work in one and not the other and how to overcome this error?
I was able to get this working on the Prod instance by making some adjustments using this answer as a guide:
By updating my call to New-WebServiceProxy to add a Class and Namespace flag, I was able to update the script in the following ways:
...
# Add Class and Namespace flags to New-WebServiceProxy call
$rs = New-WebServiceProxy -Class 'RS' -Namespace 'RS' -Uri $webServiceUrl -Credential $Cred
 
$reports = $rs.ListChildren("/Business and Technology Solutions", $true) | Where-Object { $_.TypeName -eq "Report" }
# Declare new "ScheduleDefintion object using the Class declared in the New-WebServiceProxy call
$schedDef = New-Object RS.ScheduleDefinition
$warning = #();
foreach ($report in $reports) {
# Referencing the "Item" property from the ScheduleDefinition
$execType = $rs.GetExecutionOptions($report.Path, [ref]$schedDef.Item)
...
I don't think the adding of the Class and Namespace flags on the New-WebServiceProxy call was exactly what did it, as I think it's just a cleaner way to ensure you're getting the proper Namespace from the WebService. Maybe just a little sugar.
I think the key change was making sure to the "Item" property from the schedule definition object, although I'm not sure why it was working in Dev without doing so...

Using powershell to download an embedded video

I need to download a monthly broadcast automatically (will set a scheduled task) using powershell.
Here is the embedded URL: https://www.jw.org/download/?fileformat=MP4&output=html&pub=jwb&issue=201601&option=TRGCHlZRQVNYVrXF&txtCMSLang=E
The only thing that changes each month is the 201602, 201603, etc. Once I have able to pull the 720p video file, I will work on programmatically adding that part of the URL, based on the current system clock (I can manage this)
I have tried these without success:
Attempt 1:
$source = "https://www.jw.org/download/?fileformat=MP4&output=html&pub=jwb&issue=201601&option=TRGCHlZRQVNYVrXF&txtCMSLang=E"
$destination = "c:\broadcasts\test.mp4"
Invoke-WebRequest $source -OutFile $destination
Attempt 2:
$source = "https://www.jw.org/download/?fileformat=MP4&output=html&pub=jwb&issue=201601&option=TRGCHlZRQVNYVrXF&txtCMSLang=E"
$dest = "c:\broadcasts\test.mp4"
$wc = New-Object System.Net.WebClient
$wc.DownloadFile($source, $dest)
Attempt 3:
Import-Module BitsTransfer
$url = "https://www.jw.org/download/?fileformat=MP4&output=html&pub=jwb&issue=201601&option=TRGCHlZRQVNYVrXF&txtCMSLang=E"
$output = "c:\broadcasts\test.mp4"
Start-BitsTransfer -Source $url -Destination $output
Both of these end up with a test.mp4 that is basically just an empty file.
Then I found the another page that holds the video (and the download links for different qualities) and tried to pull these links using the following (I know I could have used $webpage.links):
Attempt 4:
$webpage=Invoke-webrequest "http://tv.jw.org/#en/video/VODStudio/pub-
jwb_201601_1_VIDEO"
$webpage.RawContent | Out-File "c:\scripts\webpage.txt" ASCII -Width 9999
And found that the raw content doesn't have the mp4 visible. My idea was to pull the raw content, parse it with regex and grab the 720p URL, save it in a variable and then send that to a BitsTransfer bit of code.
Please help?