How to call powershell function properly? - function

I wrote a function to convert the input month parameter to a certain format. such as if I passed 04 to the function and the function will return the "_APR_". the function I wrote is like below:
function GetEnMonth()
{
param([string] $month)
switch ($month)
{
($_ -eq "01"){$result = "_JAN_"}
($_ -eq "02"){$result = "_FEB_"}
($_ -eq "03"){$result = "_MAR_"}
($_ -eq "04"){$result = "_APR_"}
($_ -eq "05"){$result = "_MAY_"}
($_ -eq "06"){$result = "_JUN_"}
($_ -eq "07"){$result = "_JUL_"}
($_ -eq "08"){$result = "_AUG_"}
($_ -eq "09"){$result = "_SEP_"}
($_ -eq "10"){$result = "_OCT_"}
($_ -eq "11"){$result = "_NOV_"}
($_ -eq "12"){$result = "_DEC_"}
default {$result ="_No_Result_"}
}
return [string]$result;
}
Then I use below command to execute the function to get the result:
$mYear = $today.substring(0,4)
$mMonth =$today.substring(4,2)
$mDate = $today.substring(6,2)
$monthInEn = GetEnMonth $mMonth
well, the result is always "_No_Result_", why? below is the exception:
**** Exception type : System.Management.Automation.RuntimeException
**** Exception message : You cannot call a method on a null-valued expression.
Could anyone give me an answer for this?
I have searched Google a lot but don't find useful solutions.

This should work:
function GetEnMonth
{
param([string] $month)
switch ($month)
{
"01"{$result = "_JAN_"}
"02"{$result = "_FEB_"}
"03"{$result = "_MAR_"}
"04"{$result = "_APR_"}
"05"{$result = "_MAY_"}
"06"{$result = "_JUN_"}
"07"{$result = "_JUL_"}
"08"{$result = "_AUG_"}
"09"{$result = "_SEP_"}
"10"{$result = "_OCT_"}
"11"{$result = "_NOV_"}
"12"{$result = "_DEC_"}
default {$result ="_No_Result_"}
}
return [string]$result;
}

Here's my take on this. I changed the parameter type to Int, with this you'll be able to get process such as "03" or 3. I also added break statements to make the switch work faster.
function GetEnMonth
{
param([int] $month)
switch ($month)
{
1 {"_JAN_"; break}
2 {"_FEB_"; break}
3 {"_MAR_"; break}
4 {"_APR_"; break}
5 {"_MAY_"; break}
6 {"_JUN_"; break}
7 {"_JUL_"; break}
8 {"_AUG_"; break}
9 {"_SEP_"; break}
10 {"_OCT_"; break}
11 {"_NOV_"; break}
12 {"_DEC_"; break}
default {"_No_Result_"}
}
}

Your switch statment is wrong try this:
function GetEnMonth()
{
param([string] $month)
switch ($month)
{
"01" {$result = "_JAN_"}
"02" {$result = "_FEB_"}
"03" {$result = "_MAR_"}
"04" {$result = "_APR_"}
"05" {$result = "_MAY_"}
"06" {$result = "_JUN_"}
"07" {$result = "_JUL_"}
"08" {$result = "_AUG_"}
"09" {$result = "_SEP_"}
"10" {$result = "_OCT_"}
"11" {$result = "_NOV_"}
"12" {$result = "_DEC_"}
default {$result ="_No_Result_"}
}
return [string]$result;
}

This is not an answer, but another way to do the same in one line and with a culture param:
$month = 3
$smonth=[string]::format([System.Globalization.CultureInfo]"en-US", "_{0:MMM}_",[datetime]("$month/01"))
$smonth
_MAR_

Related

Powershell - JSON format to PAC file convert

I have used the following code to display JSON results but now need to change the script to display the output instead of side by side. I have tried a script like below, but just cant seem to get it to do what I want.
My question is :
I want to remove || before the last bracket. if (shExpMatch(host, "*.lync.com") || shExpMatch(host, "*.teams.microsoft.com") || shExpMatch(host, "teams.microsoft.com") || ) As a result , it will be if (shExpMatch(host, "*.lync.com") || shExpMatch(host, "*.teams.microsoft.com") || shExpMatch(host, "teams.microsoft.com"))
I need to change the script to display the my desired output instead of side by side.
Here is my script :
$result = Invoke-WebRequest "https://endpoints.office.com/endpoints/worldwide?noipv6&ClientRequestId=b10c5ed1-bad1-445f-b386-b919946339a7"
$services = ConvertFrom-Json $result
$likeFilter = "12"
$services = $services | Where-Object { $_.id -like $likeFilter }
$urls = [System.Collections.ArrayList]#()
$services
function add_url($url){
if(!$urls.Contains($url)){ $urls.Add($url); }
}
foreach($service in $services){
foreach($url in $service.urls){ add_url($url);
}
}
# OUTPUT
$txt_proxypacText += "// This PAC file will provide proxy config to Microsoft 365 services`r`n"
$txt_proxypacText += "// using data from the public web service for all endpoints`r`n"
$txt_proxypacText += "function FindProxyForURL(url, host)`r`n"
$txt_proxypacText += "{`r`n"
$txt_proxypacText += "var direct = ""DIRECT"";`r`n"
$txt_proxypacText += "var proxyServer = ""PROXY 10.11.12.13:8080"";`r`n"
$txt_proxypacText += "host = host.toLowerCase();`r`n"
$txt_proxypacText += "if ("
foreach($url in $urls){
$txt_proxypacText += "shExpMatch(host, ""$url"") || "
}
$txt_proxypacText += ")`r`n"
$txt_proxypacText += "{`r`n"
$txt_proxypacText += "`r`n return direct;"
$txt_proxypacText += "`r`n}"
$txt_proxypacText += "`r`n return proxyServer;"
$txt_proxypacText += "`r`n}"
Output:
// This PAC file will provide proxy config to Microsoft 365 services
// using data from the public web service for all endpoints
function FindProxyForURL(url, host)
{
var direct = "DIRECT";
var proxyServer = "PROXY 10.11.12.13:8080";
host = host.toLowerCase();
if (shExpMatch(host, "*.lync.com") || shExpMatch(host, "*.teams.microsoft.com") || shExpMatch(host, "teams.microsoft.com") || )
{
return direct;
}
return proxyServer;
}
My Desired Output :
// This PAC file will provide proxy config to Microsoft 365 services
// using data from the public web service for all endpoints
function FindProxyForURL(url, host)
{
var direct = "DIRECT";
var proxyServer = "PROXY 10.11.12.13:8080";
host = host.toLowerCase();
if(shExpMatch(host, "*.lync.com")
|| shExpMatch(host, "*.teams.microsoft.com")
|| shExpMatch(host, "teams.microsoft.com"))
{
return direct;
}
return proxyServer;
}
I would make use of a Here-String with a preformated set of shExpMatch(..) lines.
Using that also relieves you from doubling quotes and string concatenations using +=
# demo urls
$urls = "*.lync.com", "*.teams.microsoft.com", "teams.microsoft.com"
$hostMatches = $(for ($i = 0; $i -lt $urls.Count; $i++) {
$prefix = if ($i -eq 0) { '' } else { ' || '}
'{0}shExpMatch(host, "{1}")'-f $prefix, $urls[$i]
}) -join [Environment]::NewLine
$txt_proxypacText = #"
// This PAC file will provide proxy config to Microsoft 365 services
// using data from the public web service for all endpoints
function FindProxyForURL(url, host)
{
var direct = "DIRECT";
var proxyServer = "PROXY 10.11.12.13:8080";
host = host.toLowerCase();
if ($hostMatches)
{
return direct;
}
return proxyServer;
}
"#
$txt_proxypacText
Output:
// This PAC file will provide proxy config to Microsoft 365 services
// using data from the public web service for all endpoints
function FindProxyForURL(url, host)
{
var direct = "DIRECT";
var proxyServer = "PROXY 10.11.12.13:8080";
host = host.toLowerCase();
if (shExpMatch(host, "*.lync.com")
|| shExpMatch(host, "*.teams.microsoft.com")
|| shExpMatch(host, "teams.microsoft.com"))
{
return direct;
}
return proxyServer;
}
As requested, I think the top part of the code, where you are gathering the urls in an arraylist can be done much easier.
One note before: You are using a $likeFilter variable with a string "12".
In that case, you could probably better use the -eq operator instead of the -like operator that has more use for filtering with wildcards (i.e. "12*").
For now, I'm assuming you want to get only the service with id matching "12" exactly.
$url = "https://endpoints.office.com/endpoints/worldwide?noipv6&ClientRequestId=b10c5ed1-bad1-445f-b386-b919946339a7"
$filter = 12
# get an array of urls from the service(s) that get through the filter
$urls = ((Invoke-WebRequest $url | ConvertFrom-Json) | Where-Object { $_.id -eq $filter }).urls | Select-Object -Unique
# EXAMPLE prepare begin
$urls = #(
'microsoft.com',
'*.microsoft.com',
'teams.microsoft.com',
'*.teams.microsoft.com')
# EXAMPLE prepare End
$urlLines = $urls |
ForEach-Object { return $_.Trim() } |
ForEach-Object {
if($_.StartsWith('*.')) {
return "shExpMatch(host, '$($_)')"
} else {
return "host == '$($_)'"
}}
$innerIf = [String]::Join("`r`n" + (' ' * 8) + "|| ", $urlLines)
#// $txt_proxypacText += " if ($($innerIf))"
Write-Host " if ($($innerIf))"
# Output:
# if (host == "microsoft.com"
# || shExpMatch(host, "*.microsoft.com")
# || host == "teams.microsoft.com"
# || shExpMatch(host, "*.teams.microsoft.com"))
I got this - simple counter method:
$counter = 0
foreach($url in $urls){
If ($counter -eq $urls.Count){
$txt_proxypacText += "shExpMatch(host, ""$url"") `r`n"
}else{
$txt_proxypacText += "shExpMatch(host, ""$url"") || `r`n"
}
$counter++
}
Probably needs some tidying up with the tab characters.

PowerShell - Cannot reference attributes of elements in array returned by .getElementsByTagName()

I am retrieving an array of elements from a webpage via .getElementsByTagName(). I am then looping through the array and printing out the elements' titles:
$links = $ie.document.GetElementsByTagName("a")
Foreach($link in $links)
{
$link.title
}
This works. However a for loop better suits my needs, and this only seems to print out blank lines:
$links = $ie.document.GetElementsByTagName("a")
for($i=0; $i -lt $links.length; $i++)
{
$links[$i].title
}
Why does the second loop not print the title?
The 6 methods below all print all link titles, except Select-Object also prints an empty line when the title attribute is missing:
$requestUri = "http://google.com"
$ie = New-Object -ComObject "InternetExplorer.Application"
$ie.Navigate($requestUri)
while($ie.Busy) { Start-Sleep -Milliseconds 250 }
$links = $ie.Document.getElementsByTagName("a")
Write-Warning "ForEach-Object:"
$links | ForEach-Object { $_.title }
Write-Warning "Select-Object:"
$links | Select-Object title
Write-Warning "foreach:"
foreach($link in $links) { $link.title }
Write-Warning "for (from 0):"
for($i = 0; $i -lt $links.Length; $i++) {
$links[$i].title
}
Write-Warning "for (from 1):"
for($i = 1; $i -le $links.Length; $i++) {
$links[$i].title
}
Write-Warning "while:"
$i = 0
while($links[$i]) {
$links[$i].title
$i++
}
$ie.Quit()
Can you please try to run this on your system?
I would guess that $links = $ie.document.GetElementByTagName("a") and
and $links = $varDiv.GetElementsByTagName("a") are not Equivalent in that they are not providing you with the same object type.

How to return only one user and date for Created By and Created Date column using PowerShell

I have a script that outputs to CSV all items and files from Libraries and Lists in a Site shown below:
Add-PSSnapin microsoft.sharepoint.powershell
$excludeLists = #("Master Page Gallery",
"Workflows",
"Workflow History"
)
function Get-DocInventory([string]$siteUrl) {
$web = Get-SPWeb "http://contoso.com/sites/depts/HBG"
foreach ($list in $web.Lists) {
if($excludeLists -notcontains $list.Title){
foreach ($item in $list.Items) {
foreach($version in $item.Versions){
$personField = $item.Fields.GetField("Author");
$authorObject = $personField.GetFieldValue($item["Author"]);
$authorName = $authorObject.LookupValue;
$userField = $version.Fields.GetField("Editor");
$editorObject = $userField.GetFieldValue($version["Editor"]);
$editorName = $editorObject.LookupValue;
$localOffset = +5;
$modified = $version["Modified"] -as [datetime];
if($modified.IsDaylightSavingTime()){$localOffset += 1;}
$modifiedLocal = $modified.addHours(-$localOffset);
$data = #{
"Version" = $version.VersionLabel
"List Name" = $list.Title
"Created By" = $authorName
"Created Date" = ($item["Created"] -as [datetime]).DateTime
"Modified By" = $editorName
"Modified Date" = ($modifiedLocal -as[datetime]).DateTime
"Item Name" = $item.Name
}
New-Object PSObject -Property $data | Select "List Name", "Item Name", "Version", "Created By", "Created Date", "Modified By", "Modified Date"
}
}
$web.Dispose();
}
}
}
Get-DocInventory | Export-Csv -NoTypeInformation -Path C:\AuditReport.csv
Below is a sample of what the script outputs:
The output above shows a file called Lions.pdf with 3 versions. In addition, this displays which user made the change at a specific version of the file. My question is, is there a way to return the user's name in the Created By column and the Created Date only once instead of it repeating for each version of the file? If so, can someone show me how as I have been having a hard time.
Below is the desired output that displays the user's name once in the Created By column and the Created Date shows only once as well:
This may be a bit dirty, but that would be my first approach to accomplish this.
At each loop iteration, you compare the values of $authorName and $createdDate with their values during the previous iteration. If they're equal, you erase the values.
Add-PSSnapin Microsoft.Sharepoint.Powershell
$excludeLists = #("Master Page Gallery",
"Workflows",
"Workflow History")
function Get-DocInventory([string]$siteUrl) {
$web = Get-SPWeb "http://contoso.com/sites/depts/HBG"
foreach ($list in $web.Lists) {
if($excludeLists -notcontains $list.Title) {
foreach ($item in $list.Items) {
$tempCreatedBy = ""
$tempCreatedDate = ""
foreach($version in $item.Versions) {
$personField = $item.Fields.GetField("Author")
$authorObject = $personField.GetFieldValue($item["Author"])
$authorName = $authorObject.LookupValue
if($authorName -eq $tempCreatedBy) { $authorName = "" } else { $tempCreatedBy = $authorName }
$createdDate = ($item["Created"] -as [datetime]).DateTime
if($createdDate -eq $tempCreatedDate) { $createdDate = "" } else { $tempCreatedDate = $createdDate }
$userField = $version.Fields.GetField("Editor")
$editorObject = $userField.GetFieldValue($version["Editor"])
$editorName = $editorObject.LookupValue
$localOffset = +5
$modified = $version["Modified"] -as [datetime]
if($modified.IsDaylightSavingTime()){ $localOffset += 1 }
$modifiedLocal = $modified.addHours(-$localOffset)
$data = #{
"Version" = $version.VersionLabel
"List Name" = $list.Title
"Created By" = $authorName
"Created Date" = $createdDate
"Modified By" = $editorName
"Modified Date" = ($modifiedLocal -as[datetime]).DateTime
"Item Name" = $item.Name
}
New-Object PSObject -Property $data | Select "List Name", "Item Name", "Version", "Created By", "Created Date", "Modified By", "Modified Date"
}
}
$web.Dispose();
}
}
}
Get-DocInventory | Export-Csv -NoTypeInformation -Path C:\AuditReport.csv

Function returns value to console but not to file

Trying to write a function to create a new line to be added to a table for export. The following outputs the correct values to the console but the CSV is empty.
If I place the code to create $newline at various point in the script it works fine but not when I call it as a function.
$report = #()
Function CreateNewLine
{
$lineproperties = #{
Cluster = $cluster
Node = $node
Database = $d.Name
LogCount = $logcount
LogPath = $p
}
$newline = New-Object PSObject -property $lineproperties
}
# Loop to create values for $cluster etc...
CreateNewLine
$report += $newline
# End loop
$report | Export-CSV 'pathto file' -notype
You have a scope issue here. $newline has no context outside the function. Therefore you would just be adding $null to the $report array. Make the function return the value which can then be captured.
Function CreateNewLine
{
$lineproperties = #{
Cluster = $cluster
Node = $node
Database = $d.Name
LogCount = $logcount
LogPath = $p
}
New-Object PSObject -property $lineproperties
}
# Loop to create values for $cluster etc...
$report += CreateNewLine
The function should have access to those other variables as long as they are in the parent scope of the function.
The function CreateNewLine never returns a value. You need to do the following:
Function CreateNewLine
{
$lineproperties = [PSCustomObject]#{
Cluster = $cluster
Node = $node
Database = $d.Name
LogCount = $logcount
LogPath = $p
}
$lineProperties
}
You can create an object in much easier manner (as Matt said, this works in Powershell 3.0 and later):
Function CreateNewLine
{
[pscustomobject]#{
Cluster = $cluster
Node = $node
Database = "name"
LogCount = $logcount
LogPath = $p
}
}
Then, in any place you want you can use this function:
$cluster = "cluster 1"
$report += createnewline
$cluster = "cluster 2"
$report += createnewline
$report | Export-CSV 'pathto file' -notype

Converting output of `hg history` into a dot file

How can I take the output of hg history and convert it into a dot file?
You are looking for this extension.
I wrote a script to do this (and called it hghistory2dot.pl). See its usage below the code:
#!/usr/bin/perl
print "digraph {\n";
$first = 1;
$cset = ();
sub printedge {
my $one = csetstr(shift(#_));
my $two = csetstr(shift(#_));
print $one, " -> ", $two, ";\n";
}
sub csetstr {
my $csetid = shift(#_);
$csetid =~ s/\s//;
$csetid =~ s/\\n//;
return "cset_" . $csetid;
}
while($line = <> ) {
if (!($line eq "\n") ) {
$line =~ s/\n/\\n/;
push(#cset, $line);
}
else {
print csetstr($current), " [shape=record label=\"", #cset, "\"];\n";
#cset = ();
}
if( $line =~ m/^changeset/ ) {
#arr = split(/:/, $line);
$arr[2] =~ s/\s//;
if( ! $parent_found && ! $first) {
#previous changeset had no defined parent; therefore this one is the implied parent.
printedge($current, $arr[2]);
}
$current = $arr[2];
$parent_found = 0;
$first = 0;
}
elsif($line =~ m/^parent/) {
$parent_found = 1;
#arr = split(/:/, $line);
$arr[2] =~ s/\s//;
printedge($current, $arr[2]);
}
}
print "}\n";
hg history | hghistory2dot.pl | dot -Tpng > tree.png