The purpose of the scripts is to catch wrong logins to Elasticsearch, and gave the opportunity to retry entering a password. The idea was to count loop iteration by adding i++ after $result = Invoke-RestMethod $uri -Credential $credential step, but it turned out that -ErrorAction SilentlyContinue process is ignored in case it's located in try{} section, so i moved loop counts into finally {$i++} section, but the cons is that the last Attempt 5 does not pass the condition while ($i -lt 6) cuz it is 5+1 in finally {$i++} section.
$elasticsearch_pass = Read-Host "Enter ELASTICSEARCH password"
$uri = "https://${elasticsearch_ip}:9200"
$user = "static_user"
$i = 1
while ($i -lt 6) {
try {
Write-Host -ForegroundColor Cyan `n ("Trying to connect to elasticsearch. Attempt $i")
$secpasswd = ConvertTo-SecureString $elasticsearch_pass -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($user, $secpasswd)
$result = Invoke-RestMethod $uri -Credential $credential
if ($result.tagline -eq 'You Know, for Search') {
Write-Host -ForegroundColor Green `n ("Connection to elasticsearch {0} established..." -f $elasticsearch_ip)
break
}
}
catch {
Write-Host -ForegroundColor Red $_
if ("$_" -eq "Unauthorized") {
$elasticsearch_pass = Read-Host `n "Wrong elasticsearch password! Pls enter correct one"
}
}
finally {$i++}
}
What is the best approach to set a static loop iteration count and execute the last Attempt?
Why use While, if an interation var is needed the usual solution is a traditional for:
$uri = "https://${elasticsearch_ip}:9200"
$user = "static_user"
$i = 1
$maxTry = 5
For( $i = 1; $i -le $maxTry; ++$i )
{
try {
Write-Host -ForegroundColor Cyan `n ("Trying to connect to elasticsearch. Attempt $i of $maxtry ")
$secpasswd = ConvertTo-SecureString $elasticsearch_pass -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($user, $secpasswd)
$result = Invoke-RestMethod $uri -Credential $credential
if ($result.tagline -eq 'You Know, for Search') {
Write-Host -ForegroundColor Green `n ("Connection to elasticsearch {0} established..." -f $elasticsearch_ip)
break
}
}
Catch {
Write-Host -ForegroundColor Red $_.Exception.Message
if ($_.Exception.Message -match "Unauthorized") {
}
}
}
In either case I don't think you need to do the ++$i in the finally block, you could just do in the catch and continue. However the for loop allows you to do it at the right point in each iteration without the confusion.
Also added $maxTry gives a slightly better echo...
Since this is interactive I changed some of the catch block to echo a little more cleanly.
Also moved the Read-Host into the loop. and changed the language a little. though there are a couple of ways to do that...
Related
Hey Everyone so I am able to set the sharepoint sites sensitivity labels in my tenant by doing them individually using the following commands:
# Get the label (required ExchangeOnlineManagement module)
Connect-IPPSSession -userprincipalname wise#redacted
$c = Get-Credential wise#redacted
Connect-SPOService -Url https://redacted-admin.sharepoint.com -Credential $c -ModernAuth:$true -AuthenticationUrl https://login.microsoftonline.com/organizations
Set-SPOSite -identity {site_url} -SensitivityLabel:'{GUID of sens label here}'
And now I am trying to set a default label for all sites that have not been manually set by users with the following code, but its throwing the "Site already has a sensitivity label" message, meaning the if statement isnt triggering when ran from a site in a variable???
# Get the label (required ExchangeOnlineManagement module)
Connect-IPPSSession -userprincipalname wise#redacted
$c = Get-Credential wise#redacted
Connect-SPOService -Url https://redacted-admin.sharepoint.com -Credential $c -ModernAuth:$true -AuthenticationUrl https://login.microsoftonline.com/organizations
#Create a progress counter and fail counter
$count = 0
$fail = 0
#get all sites
write-host "Collecting site data" -ForegroundColor Yellow
$SiteCollections = Get-SPOSite -Limit All
write-host "Collecting site data - COMPLETED" -ForegroundColor Green
#get a count of total sites
$total = $SiteCollections.count
write-host "There are $total total sites." -ForegroundColor Green
foreach ($site in $SiteCollections){
$count++
try{
if ( $site.SensitivityLabel -eq '' ){
Set-SPOSite $site -SensitivityLabel:'{GUID}'
} else {
$label = $site.SensitivityLabel
Write-host "Site already has a sensitivity label: $label"
$site.Url | Out-File '.\Sites_already_labeled.txt' -Append
}
} catch {
$sitename = $site.Name
"Bad site: $sitename" | Out-File '.\Failed_change_sites.txt' -Append
$fail++
Write-Host "Failed site count = $fail" -ForegroundColor Blue
Write-Host "Failed site = $sitename" -ForegroundColor Blue
}
Write-Host "Processing Site $count of $total" -ForegroundColor Red
}
I have tested the if sens label = '' on singular sites and it does infact fufill the if statement so im completely lost.
Thanks ChatGPT!
It's likely that the issue is with the following line of code: if ( $site.SensitivityLabel -eq '' ). The SensitivityLabel property of a SharePoint Online site may not be an empty string when it has no label applied to it. Instead, it may be $null, so the if statement should be updated to if ( $site.SensitivityLabel -eq $null ).
I wrote out a PowerShell Script to rename my computer, add it to specific OU's and join it to the domain. My question is we have two types of computer Desktop (DT) and Laptop (LT) and we give it an asset tag and I would like for it to ask me to select if it is a desktop or laptop and then ask for the asset tag number and then add the DT or LT in front of the asset tag number as the computer name (sorry if confused) example: DT01234 or LT01235. I will post my code below and bold the area that renames the computer. Any and all help would be greatly appreciated.
Write-Host "Select Desktop or Laptop [1-2] [Default 1]:
1. Desktop
2. Laptop"
$computertype = Read-Host
Write-Host "Please Enter Asset Tag"
$NewCompName = Read-Host
$renamecomputer = $true
if ($NewCompName -eq "" -or $NewCompName -eq $env:COMPUTERNAME) {$NewCompName = $env:COMPUTERNAME; $renamecomputer = $false}
Write-Host "Please enter your desired location [1-7] [Default 1]:
1. Test
2. Compliance Stations
3. Controls Stations
4. Processing Stations
5. QC Stations
6. Receiving Stations
7. Shipping Stations"
$ou = Read-Host
#$creds = Get-Credential
function Test-ADCrential{
[CmdletBinding()]
param(
[pscredential]$Credential
)
try {
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
if(!$Credential) {
$Credential = Get-Credential -EA Stop
}
if($Credential.username.split("\").count -ne 2) {
throw "You haven't entered credentials in DOMAIN\USERNAME format. Given value : $($Credential.Username)"
}
$DomainName = $Credential.username.Split("\")[0]
$UserName = $Credential.username.Split("\")[1]
$Password = $Credential.GetNetworkCredential().Password
$PC = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Domain, $DomainName)
if($PC.ValidateCredentials($UserName,$Password)) {
Write-Verbose "Credential validation successful for $($Credential.Username)"
return $True
} else {
throw "Credential validation failed for $($Credential.Username)"
}
} catch {
Write-Verbose "Error occurred while performing credential validation. $_"
return $False
}
}
$mycreds = Get-Credential
Write-Host "Adding $NewCompName to the domain"
Read-Host "Press enter to change computer name"
if ($renamecomputer -eq $true)
{Rename-Computer -NewName $NewCompName -DomainCredential $mycreds}
Read-Host "Press enter to restart computer"
Restart-Computer
Looks like you want something like this
if ($NewCompName -eq "" -or $NewCompName -eq $env:COMPUTERNAME)
{
$NewCompName = $env:COMPUTERNAME; $renamecomputer = $false
}
elseif($NewCompName -inotmatch "^DT|^LT")
{
switch($computertype )
{
1{$NewCompNamePrefix = "DT"}
2{$NewCompNamePrefix = "LT"}
default{}
}
$NewCompName = $NewCompNamePrefix + $NewCompName
}
the -inotmatch is just making sure that if a $newcompname is inputted that already looks like DTwhatever or LTwhatever, it won't append an extra LT or DT
Unrelated (just me being a bit nitpicky):
Look into Read-host -Prompt and nest the prompts into do while loops, so you can validate that the input is what you're expecting.
something like this
$properChoices = #("a","b","c")
do
{
$choice = (Read-Host -Prompt "pick a, b, or c").ToLower()
switch($choice)
{
"a"{"You picked $choice"}
"b"{"You picked $choice"}
"c"{"You picked $choice"}
default{Write-Warning "Invalid Input"}
}
}
while($choice -notin $properChoices)
I got a little powershell problem troubling me for quite a while now.
Im trying to get information from a RSS site. I download the XML and go through it. I just want certain stuff from it. That for I use .document.getElementByID().outerText
The problem is that somehow it pulls the first information correctly but after that everything fails he just picks random text or just keeps the one text from the beginning without refreshing the variable. Also Powershell ISE says "You cannot call a method on a null-valued expression." randomly.
Here is my code:
<#
AUTHOR: KOCH,MICHAEL [GRE-IT]
DESCRIPTION: RSS READER
DATE: 28.06.17
DATE LAST WRITTEN: 19.07.17
LAST CHANGE:
#>
$debug = 1 #DEBUG
$receiver="A#MailAdress.com"
$sender="A#MailAdress.com"
$smtp="A.SMTP.SERVER"
$encoding = [System.Text.Encoding]::UTF8
$path_config = "C:\RSS\Zoll\config.txt"
$output = "C:\RSS\Zoll\meldung.html"
$output_edit_path = "C:\RSS\Zoll\meldung_edit.html"
$nmbr=0
$count=0
Invoke-WebRequest -Uri 'http://www.zoll.de/SiteGlobals/Functions/RSSFeed/DE/RSSNewsfeed/RSSZollImFokus.xml' -OutFile C:\RSS\Zoll\meldungen.xml -ErrorAction Stop
[xml]$content = Get-Content C:\RSS\Zoll\meldungen.xml
$feed = $content.rss.channel
$tag = #()
if($lines=Get-Content $path_config | Measure-Object -Line) #gets the number of lines
{
while($count -ne $lines.Lines)
{
if($entrys=(Get-Content $path_config)[$nmbr]) #gets the entrys from config.txt and goes through line by line
{
$entrys >> $tag[$nmbr]
if ($debug -eq 1)
{
Write-Output "$tag[$nmbr]"
Write-Output "$entrys"
Write-Output "$count"
}
}
$count++
$nmbr++ #jumps into the next line
}
}
$ie = New-Object -ComObject "InternetExplorer.Application"
Foreach($msg in $feed.Item)
{
$link = ($msg.link)
$subject = ($msg.title)
$ie.navigate("$link")
#$return = Invoke-WebRequest -Uri $link -OutFile "C:\RSS\Zoll\link.html"
$return = $ie.document
$innertext = $return.documentElement.document.getElementById("main").outerText
$body = $innertext#.Replace('Ä', 'Ä')
<#
$body = $innertext.Replace('ä', 'ä')
$body = $innertext.Replace('Ö', 'Ö')
$body = $innertext.Replace('ö', 'ö')
$body = $innertext.Replace('Ü', 'Ü')
$body = $innertext.Replace('ü', 'ü')
$body = $innertext.Replace('ß', 'ß')
#>
if ($debug -eq 1)
{
Write-Output "Subject $subject"
Write-Output "Tag $tag"
Write-Output "Link $link"
Write-Output $body
#exit
}
if($link -match "Zigaretten") #searchs in the <link> for the string "Zigaretten"
{
if($subject -match $tag) #searches for the specified tag in config.txt !!! only one argument per line !!!
{
if($mail = Send-MailMessage -From "$sender" -To "$receiver" -Subject "Zoll Meldung: $subject" -Body "$body" -SmtpServer "$smtp" -BodyAsHtml -encoding $encoding)
{
if($debug -eq 1)
{
Write-Output "$tag"
Write-Output "Send. Tag = $tag"
}
Write-Output "Send."
}
}
}
else
{
Write-Host "Empty."
}
}
$ie.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($ie)
Remove-Variable ie
Added a wait if busy loop to make sure IE loads the full html document. Thats the solution of the problem ! :)
<#
AUTHOR: KOCH,MICHAEL [GRE-IT]
DESCRIPTION: RSS READER
DATE: 28.06.17
DATE LAST WRITTEN: 20.07.17
LAST CHANGE: ADDED WAIT IF BUSY !
#>
$debug = 0 #DEBUG
$receiver="A#MailAdress.de"
$sender="A#MailAdress.de"
$smtp="A.SMTP.SERVER"
$encoding = [System.Text.Encoding]::UTF8
$path_config = "C:\RSS\Zoll\config.txt"
$output = "C:\RSS\Zoll\meldung.html"
$output_edit_path = "C:\RSS\Zoll\meldung_edit.html"
$nmbr=0
$count=0
Invoke-WebRequest -Uri 'http://www.zoll.de/SiteGlobals/Functions/RSSFeed/DE/RSSNewsfeed/RSSZollImFokus.xml' -OutFile C:\RSS\Zoll\meldungen.xml -ErrorAction Stop
[xml]$content = Get-Content C:\RSS\Zoll\meldungen.xml
$feed = $content.rss.channel
$tag = #()
if($lines=Get-Content $path_config | Measure-Object -Line) #gets the number of lines
{
while($count -ne $lines.Lines)
{
if($entrys=(Get-Content $path_config)[$nmbr]) #gets the entrys from config.txt and goes through line by line
{
$entrys >> $tag[$nmbr]
if ($debug -eq 1)
{
Write-Output "$tag[$nmbr]"
Write-Output "$entrys"
Write-Output "$count"
}
}
$count++
$nmbr++ #jumps into the next line
}
}
$ie = New-Object -ComObject InternetExplorer.Application #creates new ComObject IE
Foreach($msg in $feed.Item)
{
$link = ($msg.link)
$subject = ($msg.title)
if ($debug -eq 1)
{
$ie.visible = $true
}
$ie.navigate("$link") #navigate with Internetexplorer to the website
while ($ie.busy -and $ie.ReadyState -ne 4){ sleep -Milliseconds 200 } # if getting the website from IE.navigate is still .busy wait 200 milliseconds
$return = $ie.document
$innertext = $return.documentelement.document.IHTMLDocument3_getElementById("main").outerText #gets the outer text from the div with the element ID "main"
while ($innertext.busy -and $innertext.ReadyState -ne 4){ sleep -Milliseconds 200 } # if getting Text is .busy wait 200 milliseconds
$body = $innertext
if ($debug -eq 1)
{
Write-Output "Subject $subject"
Write-Output "Tag $tag"
Write-Output "Link $link"
Write-Output "INNERTEXT $innertext"
Write-Output "BODY $body"
#exit
}
if($link -match "Zigaretten") #searchs in the <link> for the string "Zigaretten"
{
if($subject -match $tag) #searches for the specified tag in config.txt !!! only one argument per line !!!
{
if($mail = Send-MailMessage -From "$sender" -To "$receiver" -Subject "Zoll Meldung: $subject" -Body "$body" -SmtpServer "$smtp" -BodyAsHtml -encoding $encoding)
{
Write-Output "Send."
}
}
}
else
{
Write-Host "Empty."
}
}
$ie.Quit() #----|
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($ie) # ---> Quits the Internet Explorer Session otherwise there are to many IE.exe open and no more ID's left
Remove-Variable ie
Here is my Powershell code that when i execute it, it will continually loop while waking up my internal sites
$urlFile = "C:\Users\lfouche\Desktop\url\url.txt"
foreach($site in Get-Content $urlFile){
function WakeUp([string] $url)
{
Write-Host "Waking up $url ..." -NoNewLine
$client = new-object system.net.WebClient
$client.UseDefaultCredentials = $true
$null = $client.OpenRead($url)
$client.Dispose()
Write-Host " Ok"
}
#(
Get-Content $urlFile
) | % { WakeUp $_ }
}
Well, your script can generally be improved, however I think the error is that you already iterate over Get-Content $urlFile within your foreach condition and also in the loop. Try this:
# define the wake up function once
function WakeUp
{
Param
(
[string] $url
)
Write-Host "Waking up $url ..." -NoNewLine
$client = new-object system.net.WebClient
$client.UseDefaultCredentials = $true
$null = $client.OpenRead($url)
$client.Dispose()
Write-Host " Ok"
}
$urlFile = "C:\Users\lfouche\Desktop\url\url.txt"
$sites = Get-Content $urlFile
foreach($site in $sites)
{
# call wake up for each site
WakeUp $site
}
I'm new to powershell. I read some lines on www.powershell.com. Now I need your help to solve a problem. I want to read the UUID from clients in the Network. Therefore I created a document "pcs.txt" where all PCs are stored.
$pc = Get-Content pcs.txt #Read content of file
$cred = Get-Credential “domain\user”
for ($i=0; $i -lt $pc.length; $i++) {
$Result=test-connection -ComputerName $pc[$i] -Count 1 -Quiet
If ($Result -eq 'True')
{
$uuid = (Get-WmiObject Win32_ComputerSystemProduct -ComputerName $pc[$i] -Credential $cred).UUID
$Ausgabe=$pc[$i] + ';'+$uuid
$Ausgabe
}
else
{
$Ausgabe=$pc[$i] + '; UUID nicht erhalten'
$Ausgabe
}
}
First I test if the ping works. When the ping works I try to get the uuid.
Sometimes I don't get the uuid even if the ping worked. So I would like to code a timeout, which say -> go to next pc when you don't have the uuid after 2 seconds.
Can you help me please?
Alas, there is no timeout parameter for Get-WmiObject commandlet. There is a feature request in MS Connect, but it is from 2011 and still open.
A workaround, which I haven't tested is available by using System.Management. I'll copy-and-paste it here in case the link goes dead. (And I hate SO answers that only contain links to resouces that may or may not exist...)
Function Get-WmiCustom([string]$computername,[string]$namespace,[string]$class,[int]$timeout=15){
$ConnectionOptions = new-object System.Management.ConnectionOptions
$EnumerationOptions = new-object System.Management.EnumerationOptions
$timeoutseconds = new-timespan -seconds $timeout
$EnumerationOptions.set_timeout($timeoutseconds)
$assembledpath = "\\" + $computername + "\" + $namespace
#write-host $assembledpath -foregroundcolor yellow
$Scope = new-object System.Management.ManagementScope $assembledpath, $ConnectionOptions
$Scope.Connect()
$querystring = "SELECT * FROM " + $class
#write-host $querystring
$query = new-object System.Management.ObjectQuery $querystring
$searcher = new-object System.Management.ManagementObjectSearcher
$searcher.set_options($EnumerationOptions)
$searcher.Query = $querystring
$searcher.Scope = $Scope
trap { $_ } $result = $searcher.get()
return $result
}
I found a good workaround!
http://theolddogscriptingblog.wordpress.com/2012/05/11/wmi-hangs-and-how-to-avoid-them/
Here my working code:
$pc = Get-Content pcs.txt #FILE FROM THE HARDDISK
$cred = Get-Credential “DOMAIN\USER” #
for ($i=0; $i -lt $pc.length; $i++)
{
$Result=test-connection -ComputerName $pc[$i] -Count 1 -Quiet
If ($Result -eq 'True')
{
$WMIJob = Get-WmiObject Win32_ComputerSystemProduct -ComputerName $pc[$i] -Credential $cred -AsJob
$Timeout=Wait-Job -ID $WMIJob.ID -Timeout 1 # the Job times out after 1 seconds.
$uuid = Receive-Job $WMIJob.ID
if ($uuid -ne $null)
{
$Wert =$uuid.UUID
$Ausgabe=$pc[$i] + ';'+$Wert
$Ausgabe
}
else
{
<#$b = $error | select Exception
$E = $b -split (:)
$x = $E[1]
$Error.Clear() #>
$Ausgabe=$pc[$i] + '; got no uuid'
$Ausgabe
}
}
else
{
$Ausgabe='PC not reached through ping.'
$Ausgabe
}
}
I hope I can help somebody with that