powershell -replace wont work when called by vba - regex

I have a powershell script that replace some charatere from a string. The string look like this:
1234 - A Long Project Name
I need the string to replace space for underscore so it look like this: 1234_A_Long_Project_Name
This is part of my powershell code:
...
$projet = $projet -replace '\s+-\s+','_'
$projet = $projet -replace '\s+|_+','_'
...
When I run this script directly in powershell it does what I want. The problem is that I need to call the script from a VBA macro in Outlook, when a mail is received with a particular subject this macro is fired:
sText = Split(olItem.Body, vbCrLf)
Line = Split(sText(1), ":")
If Line(0) = "Projet " Then
projet = Trim(Line(1))
retval = Shell("powershell -noexit c:\script\droit.ps1 '" & projet & "'")
End If
If i run the script with the string "1234 - Long project Name" from powershell, is give me this:
1234_Long_Project_Name
When the script is fired by vba, with the same string, it return me this:
1234_-_Long_Project_Name
Anyone have an idea why it doesn't return me the same result.
Just for info, I run the script on Win 8.1, powerhsell 4 and outlook 2013.
Thank you all
Edit:
this is the powershell script:
Param([string]$projet)
function getPass2($adminName, $encrypted, $domain){
$password = convertto-securestring -string $encrypted
$Cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $domain\$AdminName,$password
$cred
}
$projet = $projet -replace '\s+-\s+','_'
$projet = $projet -replace '\s+|_+','_'
$projet = $projet -replace 'é|è|ê','e'
$projet = $projet -replace 'à','a'
$projet = $projet -replace 'ï','i'
$projet = $projet -replace 'ç','c'
$projet
$encrypted = "123"
$AdminName = "123"
$cred = getPass2 $adminName $encrypted "123"
$exist = $false
#commande for serve1
if ($cred){
$session = New-PSSession -credential $cred -ComputerName "server"
#ScriptBlock server1
$result = Invoke-command -session $session -Args $projet -ScriptBlock {
$projet = $args[0]
#folder copy
if($projet){
$SFolder = "z:\FolderTemplate\"
$DFolder = "z:\DestinationFolder\" + $projet
$FileExists = Test-Path $DFolder
if ($FileExists -eq $false)
{
Copy-Item $SFolder $DFolder -recurse
#acl
$SFolderList = get-childitem -name $SFolder -recurse
foreach ($Folder in $SFolderList) {
$SFullPath = $SFolder + "$Folder"
$DFullPath = $DFolder + "\" + "$Folder"
$NewACL = Get-ACL "$SFullPath"
Set-ACL "$DFullPath" $NewACL
}
}
else
{
$exist = $true
return $exist
}
}
else{
echo "error"
}s
}
Remove-PsSession -session $session
$exist = $result
#Credentiel someserver
$AdminName = "123"
$encrypted = "123"
$credMTL = getPass2 $adminName $encrypted "123"
#commande for some server
if ($credMTL -and !$exist){
$session = New-PSSession -credential $credMTL -ComputerName "server2"
$result = Invoke-command -session $session -Args $projet -ScriptBlock {
$projet = $args[0]
$SFolder = "F:\Folder\template"
$DFolder = "F:\destinationFolder\" + $projet
$FileExists = Test-Path $DFolder
if ($FileExists -eq $false)
{
$shortcutName = $DFolder + "\someLink.lnk"
$shortcutTarget = "\\linkPath\" + $projet
Copy-Item $SFolder $DFolder -recurse
$shell = New-Object -COM WScript.Shell
$shortcut = $shell.CreateShortcut($shortcutName)
$shortcut.TargetPath = $shortcut.TargetPath + "\" + $projet
$shortcut.Description = $projet
$shortcut.Save()
$exist = $false
}
else {
$exist = $true
}
return $exist
}
Remove-PsSession -session $session
}
return $result
}

Ok I finaly found what appened. When I wrote the test mail in outlook, the line was changed by the auto correct feature of Outlook and the "-" was change by something else (dont know the charater, it look like an "-" but a little bit longer).
When I receive an autogenerated mail from my prod machin, it actually work very well.
Thank you every one for your help.

Related

Export data from SP 2013 list to SQL database with comment versions

I'm trying to figure out a way to get comments from all item versions into one column in a sql table and view, but still unsuccessful.
I have listed the script I wrote below, but I can't add comments to it. Second script is light foreach loop which get comments history and add in new column in item, but this is not good solution if you have more than 10 000 items in SharePoint 2013 list.
Add-pssnapin microsoft.sharepoint.powershell
cls;
# env settings
#$env = "https://sharepoint.com/"
#$sqlConnectionString = "Server=servername\servername;Database=Database;User Id=UserID;Password=UserPassword;Timeout=15"
# settings
$webUrl = "$env"
$fromListUrl = "Lists/Name"
$fromViewName = "Sharepoint list view"
$targetTableName = "Target SQL table"
$targetViewName = "Target SQL View"
$targetPrimaryKey = "DBID"
$sourcePrimaryKey = "ID"
# script internal settings
$sqlDropTable = "DROP TABLE IF EXISTS [dbo].[{TABLENAME}]"
$sqlCreateTable = "IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[{TABLENAME}]') AND type in (N'U')) BEGIN CREATE TABLE [dbo].[{TABLENAME}]( [{PRIMARYKEY}] [int] IDENTITY(1,1) NOT NULL, CONSTRAINT [PK_{TABLENAME}_{PRIMARYKEY}] PRIMARY KEY CLUSTERED ([{PRIMARYKEY}] ASC) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY] END"
$sqlCreateColumn = "IF COL_LENGTH('{TABLENAME}', '{COLUMN}') IS NULL BEGIN ALTER TABLE [dbo].[{TABLENAME}] ADD [{COLUMN}] {TYPE} END "
$sqlSelect = "SELECT $targetPrimaryKey,$sourcePrimaryKey FROM [dbo].[$targetTableName]"
$sqlInsert = "INSERT INTO [dbo].[$targetTableName]({COLUMNS}) VALUES ({VALUES})"
$sqlUpdate = "UPDATE [dbo].[$targetTableName] SET {COLUMNVALUES} WHERE [$sourcePrimaryKey] = {IDVALUE}"
$sqlCreateView = "IF NOT EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N'[dbo].[{VIEWNAME}]')) EXEC dbo.sp_executesql #statement = N'CREATE VIEW [dbo].[{VIEWNAME}] AS SELECT {COLUMNS} FROM [dbo].[{TABLENAME}]' "
$sqlDropView = "DROP VIEW IF EXISTS [dbo].[{VIEWNAME}]"
$commit = $true # false to dont make changes in shp (folders creation, files upload, log items)
$recreate = $false # true will erase target table and create new
# script variables
$wasError = $false # flag to see if script encountered any error
$connection = $null
function GetColumnFromField($field, $row)
{
$name = $field.InternalName
if([string]::IsNullOrEmpty($fieldTitle))
{
$name = $field.InternalName
}
if(($field.Type -eq "User" -or $field.Type -eq "Lookup") -and $field.hidden -eq $false)
{
$value1 = [DBNull]::Value
$value2 = [DBNull]::Value
if($row -ne $null)
{
$value = $row[$field.internalname]
if([string]::IsNullOrEmpty($value) -eq $false)
{
try
{
$lookup = New-Object Microsoft.SharePoint.SPFieldLookupValue($value)
$value1 = $lookup.LookupId
$value2 = $lookup.LookupValue
if ($value1 -eq $null) { $value1 = 0 }
if ($value2 -eq $null) { $value2 = [DBNull]::Value }
}
catch
{
$value1 = 0
$value2 = $value
}
}
}
$cols = #()
$cols += ,#("$($name)_ID", "int", $value1, "$($field.Title) ID")
$cols += ,#("$($name)_Value", "nvarchar(255)", $value2, "$($field.Title)")
return ,$cols
}
$type = "NVARCHAR(MAX)"
if($field.Type -eq "Integer" -or $field.Type -eq "Counter")
{
$type = "int"
}
elseif($field.Type -eq "Number")
{
$type = "float"
}
elseif($field.Type -eq "DateTime")
{
$type = "datetime"
}
elseif($field.Type -eq "Boolean")
{
$type = "bit"
}
elseif($field.Type -eq "Guid")
{
$type = "uniqueidentifier"
}
elseif($field.Type -eq "Text" -or $field.Type -eq "Choice")
{
$type = "nvarchar(255)"
}
elseif($field.Type -eq "Note")
{
$type = "nvarchar(MAX)"
}
$value = [DBNull]::Value
if($row -ne $null -and $row[$field.internalname] -ne $null)
{
if($field.Type -eq "Integer")
{
$value = $row[$field.internalname]
}
elseif($field.Type -eq "Number")
{
$value = $row[$field.internalname]
}
elseif($field.Type -eq "DateTime")
{
$value = [System.DateTime]$row[$field.internalname]
}
elseif($field.Type -eq "Boolean")
{
$value = $row[$field.internalname]
}
elseif($field.Type -eq "Guid")
{
$value = $row[$field.internalname]
}
elseif($field.Type -eq "Text")
{
$value = $row[$field.internalname].tostring()
}
elseif($field.Type -eq "Note")
{
$value = $row[$field.internalname].tostring()
}
else
{
$value = $row[$field.internalname].tostring()
}
if ($value -eq $null) { $value = [DBNull]::Value }
}
$cols = #()
$cols += ,#($name,$type,$value,"$($field.Title)")
return ,$cols
}
try
{
# connect to shp
write-host "Started $([DateTime]::Now.ToString()), web: $webUrl, listurl: $fromListUrl, view: $fromViewName, target: $targetTableName"
$web = get-spweb $webUrl
$list = $web.getlist($fromListUrl)
$view = $list.views[$fromViewName]
if (!$?) {throw "Could not open SHP connections."}
write-host "Connected to SHP list: $($list.title)"
# connect to sql
$connection = New-Object System.Data.SqlClient.SqlConnection $sqlConnectionString
$connection.Open()
if (!$?) {throw "Could not open SQL connections."}
write-host "Connected to SQL db: $($connection.Database)"
# recreate target table
if($recreate -eq $true)
{
$dropTableQuery = $sqlDropTable.replace("{TABLENAME}",$targetTableName)
$dropTableCommand = New-Object System.Data.SqlClient.SqlCommand $dropTableQuery, $connection
if($commit)
{
$dropTableCommand.ExecuteScalar()
}
$dropViewQuery = $sqlDropView.replace("{VIEWNAME}",$targetViewName)
$dropViewCommand = New-Object System.Data.SqlClient.SqlCommand $dropViewQuery, $connection
if($commit)
{
$dropViewCommand.ExecuteScalar()
}
}
# ensure target table
$syncTableQuery = $sqlCreateTable.replace("{TABLENAME}",$targetTableName).replace("{PRIMARYKEY}",$targetPrimaryKey)
$syncTableCommand = New-Object System.Data.SqlClient.SqlCommand $syncTableQuery, $connection
if($commit)
{
$syncTableCommand.ExecuteScalar()
}
# ensure sql table columns
$viewColumns = ""
$syncColumnsQuery = $sqlCreateColumn.replace("{TABLENAME}",$targetTableName).replace("{COLUMN}", $sourcePrimaryKey).replace("{TYPE}", "int")
for($c = 0; $c -lt $view.viewfields.count; $c++)
{
$field = $list.fields.getfieldbyinternalname($view.viewfields[$c])
$columns = GetColumnFromField -field $field -row $null
foreach($column in $columns)
{
if($column.internalname -eq "ID")
{
continue
}
write-host "Ensuring column: $($column[0]) - $($column[1])"
$syncColumnsQuery += $sqlCreateColumn.replace("{TABLENAME}",$targetTableName).replace("{COLUMN}", $column[0]).replace("{TYPE}", $column[1])
$viewColumns += "[$($column[0])] as [$($column[3])],"
}
}
$syncColumnsCommand = New-Object System.Data.SqlClient.SqlCommand $syncColumnsQuery, $connection
if($commit)
{
$syncColumnsCommand.ExecuteScalar()
}
write-host "Sql columns ensured"
# ensure sql view
if($false)
{
$createViewQuery = $sqlCreateView.replace("{TABLENAME}",$targetTableName).replace("{VIEWNAME}",$targetViewName).replace("{COLUMNS}", $viewColumns.trimend(','))
$createViewCommand = New-Object System.Data.SqlClient.SqlCommand $createViewQuery, $connection
if($commit)
{
$createViewCommand.ExecuteScalar()
}
}
# read data from sql
$imported = new-object System.Collections.Hashtable
$selectCommandQuery = $sqlSelect
$selectCommand = New-Object System.Data.SqlClient.SqlCommand $selectCommandQuery, $connection
$dr = $selectCommand.ExecuteReader()
if ($dr.HasRows)
{
while ($dr.Read())
{
$key = $dr[$sourcePrimaryKey]
$value = $dr[$targetPrimaryKey]
if($imported.containskey($key) -eq $false)
{
$imported.add($key,$value)
}
}
}
$dr.close()
write-host "Loaded already imported rows: $($imported.count)"
# read data from list
$query = new-object microsoft.sharepoint.spquery
$query.query = $view.Query
$query.ViewAttributes = "Scope='Recursive'";
#$query.RowLimit = 40
$data = $list.getitems($query)
write-host "Loaded sharepoint list items: $($data.count)"
write-host "Processing items count: $($data.count)"
foreach($row in $data)
{
$key = $row[$sourcePrimaryKey]
Write-host "Processing item: $key... " -nonewline
if($imported.containskey($key))
{
Write-host "Row found Sql ID: $($imported[$key])... " -for yellow -nonewline
# generate update query
$updateColumnValues = ""
foreach($fieldInternalName in $view.viewfields)
{
if($fieldInternalName -eq "ID")
{
continue
}
$field = $list.fields.getfieldbyinternalname($fieldInternalName)
$columns = GetColumnFromField -field $field -row $row
foreach($column in $columns)
{
#write-host "Updating value: $($column[0]) - $($column[1]) => $($column[2])"
$updateColumnValues += "[" + $column[0] + "] = #" + $column[0] + ","
}
}
Write-host "UpdateQuery generated... " -nonewline -for green
# execute insert query
$updateCommandQuery = $sqlUpdate.replace("{COLUMNVALUES}", $updateColumnValues.TrimEnd(',')).replace("{IDVALUE}", $key)
$updateCommand = New-Object System.Data.SqlClient.SqlCommand $updateCommandQuery, $connection
# add values to parameters
foreach($fieldInternalName in $view.viewfields)
{
if($fieldInternalName -eq "ID")
{
continue
}
$field = $list.fields.getfieldbyinternalname($fieldInternalName)
$columns = GetColumnFromField -field $field -row $row
foreach($column in $columns)
{
$param = $updateCommand.Parameters.AddWithValue("#" + $column[0], $column[2])
}
}
if($commit)
{
$updateCommand.ExecuteScalar()
}
Write-host "UpdateQuery executed" -for green
}
else
{
# generate insert query with parameters
$insertCommand_Part1 = "[" + $sourcePrimaryKey + "],"
$insertCommand_Part2 = $row[$sourcePrimaryKey].tostring() + ","
foreach($fieldInternalName in $view.viewfields)
{
if($fieldInternalName -eq "ID")
{
continue
}
$field = $list.fields.getfieldbyinternalname($fieldInternalName)
$columns = GetColumnFromField -field $field -row $row
foreach($column in $columns)
{
#write-host "Setting value: $($column[0]) - $($column[1]) => $($column[2])"
$insertCommand_Part1 += "[" + $column[0] + "],"
$insertCommand_Part2 += "#" + $column[0] + ","
}
}
Write-host "InsertQuery generated... " -nonewline -for green
# execute insert query
$insertCommandQuery = $sqlInsert.replace("{COLUMNS}", $insertCommand_Part1.TrimEnd(',')).replace("{VALUES}", $insertCommand_Part2.TrimEnd(','))
$insertCommand = New-Object System.Data.SqlClient.SqlCommand $insertCommandQuery, $connection
# add values to parameters
foreach($fieldInternalName in $view.viewfields)
{
if($fieldInternalName -eq "ID")
{
continue
}
$field = $list.fields.getfieldbyinternalname($fieldInternalName)
$columns = GetColumnFromField -field $field -row $row
foreach($column in $columns)
{
$param = $insertCommand.Parameters.AddWithValue("#" + $column[0], $column[2])
}
}
if($commit)
{
$insertCommand.ExecuteScalar()
}
Write-host "InsertQuery executed" -for green
}
}
}
catch
{
$wasError = $true
write-host "error occured" -for red
write-host "$([system.datetime]::now.tostring(""yyyy.MM.dd_HH.mm.ss.ffff"")) - error: $($_.Exception.Message) in script: $($_.fullname)"
write-host "$([system.datetime]::now.tostring(""yyyy.MM.dd_HH.mm.ss.ffff"")) - error details: $($_.Exception.tostring())"
write-host "$([system.datetime]::now.tostring(""yyyy.MM.dd_HH.mm.ss.ffff"")) - error stack: $($_.ScriptStackTrace)"
write-host "$([system.datetime]::now.tostring(""yyyy.MM.dd_HH.mm.ss.ffff"")) - error position: $($_.invocationinfo.positionmessage)"
}
if($connection -ne $null)
{
$connection.close()
}
if($wasError)
{
write-host "Script encountered error" -for red
}
else
{
write-host "No error occured" -for green
}
write-host "Finished $([DateTime]::Now.ToString())"
Foreach loop to get item versions and comments ->
foreach($item in $items){
foreach($version in $item.Versions)
{
if($item["ID"] -eq $($item.id)){
#$VersionData = "$($version['Odpoved'])"
if($VersionData -ne $null){
if($item['Export_Odpoved'] -ne $version['Odpoved']){
#write-host $version['Odpoved']
#write-host $VersionData.ToString();
$item["Export_Odpoved"] += $version['Odpoved']
#write-host $item["Export_Odpoved"]
$item.SystemUpdate()
write-host $item["ID"] "updated" -ForegroundColor Green
#write-host #$VersionData "||" $item["ID"] "updated" -ForegroundColor Green
} else{write-host "preskakujem ziadost, nakolko je korektne zmigrovana" $item["ID"] -ForegroundColor Yellow}
};
};
};
};
Any suggestions to make it work ? Thanks

Powershell parsing parsing error ".*\((?KB\d{6,7})\)" - Unrecognized grouping construct

Hi I'm trying to play with windows updates with PowerShell script, the script works fine but before results it through parsing error.
my script
$Session = New-Object -ComObject Microsoft.Update.Session
$Searcher = $Session.CreateUpdateSearcher()
$HistoryCount = $Searcher.GetTotalHistoryCount()
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa386532%28v=vs.85%29.aspx
$Searcher.QueryHistory(0,$HistoryCount) | ForEach-Object -Process {
$Title = $null
if($_.Title -match "\(KB\d{6,7}\)"){
# Split returns an array of strings
$Title = ($_.Title -split '.*\((?KB\d{6,7})\)')[1]
}else{
$Title = $_.Title
}
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa387095%28v=vs.85%29.aspx
$Result = $null
Switch ($_.ResultCode)
{
0 { $Result = 'NotStarted'}
1 { $Result = 'InProgress' }
2 { $Result = 'Succeeded' }
3 { $Result = 'SucceededWithErrors' }
4 { $Result = 'Failed' }
5 { $Result = 'Aborted' }
default { $Result = $_ }
}
New-Object -TypeName PSObject -Property #{
InstalledOn = Get-Date -Date $_.Date;
Title = $Title;
Name = $_.Title;
Status = $Result
}
} | Sort-Object -Descending:$true -Property nInstalledO |
Select-Object -Property * -ExcludeProperty Name | Format-Table -AutoSize -Wrap
above script works fine but before results it shows some parsing error at line
error:
parsing ".*\((?KB\d{6,7})\)" - Unrecognized grouping construct.
At B:\Clients\SirAhmad\check-updates-history.ps1:9 char:9
+ $Title = ($_.Title -split '.*\((?KB\d{6,7})\)')[1]
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], ArgumentException
+ FullyQualifiedErrorId : System.ArgumentException
at line
$Title = ($_.Title -split '.*\((?KB\d{6,7})\)')[1]
Looks regx issues.
Can someone help me out to indicate what is the issue with regix?

powershell System.Collections.Generic.List[System.String] and foreach

I'm finding that I have the following Generic List, and I can see it has items in it, but when I try to run the code, it's not hitting inside the foreach. This is my code:
function SQLQueryWriteToFile([string]$SQLquery, [string]$extractFile)
{
$sqlConnection = New-Object System.Data.SqlClient.SqlConnection
$sqlConnection.ConnectionString = "Server=blah;Database=blah;User ID=blah;Password=blah" #production #I have an error in this so it doesn't connect
$sqlConnection.Open()
if($sqlConnection.State -ne 'Open'){
$global:ErrorStrings.Add("Exception: $("Couldn't connect to DB with connection string given");; ") #this gets hit
}
###
$global:ErrorStrings = New-Object System.Collections.Generic.List[System.String] #System.Object]
$query = "Select blah"
$dir = "C:\blah"
SQLQueryWriteToFile $query $dir
$errorCodeAsString = ""
foreach ($item in $global:ErrorStrings.Members){
$errorCodeAsString += $item #this isn't hit
}
Any idea why it's not finding the error string in my list for the foreach loop, when I can see it's in there looking at $global:ErrorStrings? Based on this foreach list, I'm doing it correctly. I'm having trouble finding examples like what I'm doing. Thanks!
try this:
function SQLQueryWriteToFile([string]$SQLquery, [string]$extractFile)
{
[System.Data.SqlClient.SqlConnection] $sqlConnection=$null
[System.Data.SqlClient.SqlCommand] $command=$null
try
{
$sqlConnection = New-Object System.Data.SqlClient.SqlConnection
$sqlConnection.ConnectionString = "Server=blah;Database=blah;User ID=blah;Password=blah"
$command = New-Object System.Data.SqlClient.SqlCommand
$command.Connection=$sqlConnection
$command.CommandText=$SQLquery
$sqlConnection.Open()
$command.ExecuteNonQuery()
}
catch
{
$global:ErrorStrings.Add($_.Exception.Message)
}
finally
{
if ($sqlConnection -ne $null)
{
$sqlConnection.Close()
$sqlConnection.Dispose()
}
if ($command -ne $null)
{
$command.Dispose()
}
}
}
$global:ErrorStrings = New-Object System.Collections.Generic.List[System.String]
$query = "Select blah"
$dir = "C:\blah"
$global:ErrorStrings.Clear()
SQLQueryWriteToFile $query $dir
$errorCodeAsString=""
for ($i = 0; $i -lt $global:ErrorStrings.Count; $i++)
{
$errorCodeAsString +=$global:ErrorStrings.Item($i)
}
$errorCodeAsString

PowerShell WebServiceProxy with forms authentication

I am working on building a few interfaces with Remedy 9.1 web services. It is configured with Forms authentication to get to the WSDL. I would like to keep it in that configuration so that the more powerful web services remain protected.
I have parts of a solution, but I am not sure that they can work together, perhaps you know of a solution?
This works if I remove forms auth:
function New-ObjectFromProxy {
param($proxy, $proxyAttributeName, $typeName)
# Locate the assembly for $proxy
$attribute = $proxy | gm | where { $_.Name -eq $proxyAttributeName }
$str = "`$assembly = [" + $attribute.TypeName + "].assembly"
invoke-expression $str
# Instantiate an AuthenticationHeaderValue object.
$type = $assembly.getTypes() | where { $_.Name -eq $typeName }
return $assembly.CreateInstance($type)
}
$Now = get-date -Format G
$Q = "'System Broadcast End Date' >= """ + $Now + """"
$proxy = New-WebServiceProxy -Uri "https://mycompany-itsm.columncloud.com/arsys/WSDL/public/servername/CFG%3ABroadcast"
$authHeader = New-ObjectFromProxy -proxy $proxy -proxyAttributeName "AuthenticationInfoValue" -typeName "AuthenticationInfo"
$authHeader.userName = "username"
$authHeader.password = "password"
$proxy.AuthenticationInfoValue = $authHeader
$Response = $proxy.GetList($Q,"","")
$Response | format-Table Broadcast_Start_Date, Broadcast_Message
However, if I move the webservice back behind the forms auth, I can get to the WSDL if I do this:
#this is the url that you want will send thae request to
$url = "https://mycompany-itsm.columncloud.com/arsys/servlet/LoginServlet"
#here you can set your POST params
$parameters = "username=username&pwd=ppaasswwoorrdd&encpwd=1&ipoverride=0&initialState=-1&timezone=-28800000&goto=/arsys/WSDL/protected/servername/HPD_IncidentInterface_Create_WS"
#creating the xmlHtpp system object
$http_request = New-Object -ComObject Msxml2.XMLHTTP
$http_request.open('POST', $url, $false)
#Setting required header of the request
$http_request.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
$http_request.setRequestHeader("Content-length", $parameters.length)
#Assigning the params to the request
$Resp = $http_request.send($parameters)
echo $http_request.responseText
I would like to find a solution to combine these solutions together to use forms auth to get to the WSDL and create a webServiceProxy object. Perhaps my google-fu is weak, but I have not found a formsauth solution for new-webserviceProxy.
Origin code from POSHCODE site. updated to add formsauth
Basically I had to use the way back machine to figure out how this was done before it was made super simple by new-WebServiceProxy. I fire up a web request to post with forms auth data and grab the cookie for the conversation. If my cookie expires, I go get a new one (might explain my waistline).
Huge props to Oisin Grehan for publishing his code 7 years ago.
Call it like this:
.\New-WebServiceProxy-FormsAuth.ps1 -Url "https://mycompany/WSDL/public/servername/CFG%3ABroadcast" -Namespace "mystuff" -Cookies $CookieJar -lurl "https://mycompany/servlet/LoginServlet" -postData "username=username&pwd=ppaasswwoorrdd&encpwd=1&ipoverride=0&initialState=-1&timezone=-28800000"
# New-WebServiceProxy-FormsAuth.ps1 (v3.0 Sep 23, 2009)
#
# Oisin Grehan <oising#gmail.com> (x0n)
# ghangas
#
# Usage:
# $proxy = .\New-WebServiceProxy.ps1 [-Url] http://site/service.asmx -lurl <http://site/loginpostpage> -postData <form data url encoded> [[-SoapProtocol] <Soap | Soap12>] [-Namespace <namespace>] [-Cookies <CookieContainer>]
#
# to see available webmethods:
# $proxy | gm
#
param($url = $(throw "need `$url"), [string]$protocol = "Soap", [string]$Namespace="", [System.Net.CookieContainer]$CookieJar, [string]$lurl, [string]$postData)
[void][system.Reflection.Assembly]::LoadWithPartialName("system.web.services")
trap {
"Error:`n`n $error";
break;
}
#$request = [System.Net.WebRequest]::Create($url);
$dcp = new-object system.web.services.discovery.discoveryclientprotocol
if ($CookieJar -ne $null) {
If ($CookieJar.ToString() = "System.Net.CookieContainer") {
$dcp.CookieContainer = $CookieJar
}
}
Write-Progress "Discovery" "Searching..."
$dcp.AllowAutoRedirect = $true
try {[void]$dcp.DiscoverAny($url)
}
catch {
$CookieJar = New-Object System.Net.CookieContainer
$buffer = [text.encoding]::ascii.getbytes($postData)
[net.httpWebRequest] $req = [net.webRequest]::create($lurl)
$req.method = "POST"
$req.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
$req.Headers.Add("Accept-Language: en-US")
$req.Headers.Add("Accept-Encoding: gzip,deflate")
$req.Headers.Add("Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7")
$req.AllowAutoRedirect = $true
$req.UserAgent = "Mozilla/4.0"
$req.ContentType = "application/x-www-form-urlencoded"
$req.ContentLength = $buffer.length
$req.TimeOut = 50000
$req.KeepAlive = $true
$req.CookieContainer = $CookieJar
$reqst = $req.getRequestStream()
$reqst.write($buffer, 0, $buffer.length)
$reqst.flush()
$reqst.close()
[net.httpWebResponse] $res = $req.getResponse()
$dcp.CookieContainer = $CookieJar
[void]$dcp.DiscoverAny($url)
}
$dcp.ResolveAll()
# get service name
foreach ($entry in $dcp.Documents.GetEnumerator()) { # needed for Dictionary
if ($entry.Value -is [System.Web.Services.Description.ServiceDescription]) {
$script:serviceName = $entry.Value.Services[0].Name
Write-Verbose "Service: $serviceName"
}
}
Write-Progress "WS-I Basic Profile 1.1" "Validating..."
$ns = new-Object System.CodeDom.CodeNamespace $Namespace
$wref = new-object System.Web.Services.Description.WebReference $dcp.Documents, $ns
$wrefs = new-object system.web.services.description.webreferencecollection
[void]$wrefs.Add($wref)
$ccUnit = new-object System.CodeDom.CodeCompileUnit
[void]$ccUnit.Namespaces.Add($ns)
$violations = new-object system.web.Services.Description.BasicProfileViolationCollection
$wsi11 = [system.web.services.WsiProfiles]::BasicProfile1_1
if ([system.web.Services.Description.WebServicesInteroperability]::CheckConformance($wsi11, $wref, $violations)) {
Write-Progress "Proxy Generation" "Compiling..."
$webRefOpts = new-object System.Web.Services.Description.WebReferenceOptions
$webRefOpts.CodeGenerationOptions = "GenerateNewAsync","GenerateProperties" #,"GenerateOldAsync"
#StringCollection strings = ServiceDescriptionImporter.GenerateWebReferences(
# webReferences, codeProvider, codeCompileUnit, parameters.GetWebReferenceOptions());
$csprovider = new-object Microsoft.CSharp.CSharpCodeProvider
$warnings = [System.Web.Services.Description.ServiceDescriptionImporter]::GenerateWebReferences(
$wrefs, $csprovider, $ccunit, $webRefOpts)
if ($warnings.Count -eq 0) {
$param = new-object system.CodeDom.Compiler.CompilerParameters
[void]$param.ReferencedAssemblies.Add("System.Xml.dll")
[void]$param.ReferencedAssemblies.Add("System.Web.Services.dll")
$param.GenerateInMemory = $true;
#$param.TempFiles = (new-object System.CodeDom.Compiler.TempFileCollection "c:\temp", $true)
$param.GenerateExecutable = $false;
#$param.OutputAssembly = "$($ns.Name)_$($sdname).dll"
$param.TreatWarningsAsErrors = $false;
$param.WarningLevel = 4;
# do it
$compileResults = $csprovider.CompileAssemblyFromDom($param, $ccUnit);
if ($compileResults.Errors.Count -gt 0) {
Write-Progress "Proxy Generation" "Failed."
foreach ($output in $compileResults.Output) { write-host $output }
foreach ($err in $compileResults.Errors) { write-warning $err }
} else {
$assembly = $compileResults.CompiledAssembly
if ($assembly) {
if ($namespace) {
$serviceType = $assembly.GetType($namespace + "." + $serviceName)
} else {
$serviceType = $assembly.GetType($serviceName)
}
$assembly.GetTypes() | % { Write-Verbose $_.FullName }
} else {
Write-Warning "Failed: `$assembly is null"
return
}
# return proxy instance
$proxy = new-object $serviceType.FullName
$proxy # dump instance to pipeline
}
} else {
Write-Progress "Proxy Generation" "Failed."
Write-Warning $warnings
}
#Write-Progress -Completed
}

Powershell function to replace or add lines in text files

I'm working on a powershell script that modifies config files. I have files like this:
#####################################################
# comment about logentrytimeout
#####################################################
Logentrytimeout= 1800
who should look like this:
#####################################################
# comment about logentrytimeout
#####################################################
Logentrytimeout= 180
disablepostprocessing = 1
segmentstarttimeout = 180
If there is a key set(Logentrytimeout), just update it to the given value. Ignore comments, where the key is mentioned(lines that start with #). The Key is case insensitive.
If the key is not set(disablepostprocessing and segmentstarttimeout), append key and value to the file. My function so far goes like this:
function setConfig( $file, $key, $value )
{
(Get-Content $file) |
Foreach-Object {$_ -replace "^"+$key+".=.+$", $key + " = " + $value } |
Set-Content $file
}
setConfig divider.conf "Logentrytimeout" "180"
setConfig divider.conf "disablepostprocessing" "1"
setConfig divider.conf "segmentstarttimeout" "180"
What is the correct regex?
How do I check if there was a replacement?
If there was no replacement: How can I append $key+" = "+$value to the file then?
Assuming the $key you want to replace is always at the beginning of a line, and that it contains no special regex characters
function setConfig( $file, $key, $value ) {
$content = Get-Content $file
if ( $content -match "^$key\s*=" ) {
$content -replace "^$key\s*=.*", "$key = $value" |
Set-Content $file
} else {
Add-Content $file "$key = $value"
}
}
setConfig "divider.conf" "Logentrytimeout" "180"
If there is no replacement $key = $value will be appended to the file.
Updated version of the functions above with some parametrisation and verbose output if required.
Function Set-FileConfigurationValue()
{
[CmdletBinding(PositionalBinding=$false)]
param(
[Parameter(Mandatory)][string][ValidateScript({Test-Path $_})] $Path,
[Parameter(Mandatory)][string][ValidateNotNullOrEmpty()] $Key,
[Parameter(Mandatory)][string][ValidateNotNullOrEmpty()] $Value,
[Switch] $ReplaceExistingValue,
[Switch] $ReplaceOnly
)
$content = Get-Content -Path $Path
$regreplace = $("(?<=$Key).*?=.*")
$regValue = $("=" + $Value)
if (([regex]::Match((Get-Content $Path),$regreplace)).success)
{
If ($ReplaceExistingValue)
{
Write-Verbose "Replacing configuration Key ""$Key"" in configuration file ""$Path"" with Value ""$Value"""
(Get-Content -Path $Path) | Foreach-Object { [regex]::Replace($_,$regreplace,$regvalue) } | Set-Content $Path
}
else
{
Write-Warning "Key ""$Key"" found in configuration file ""$Path"". To replace this Value specify parameter ""ReplaceExistingValue"""
}
}
elseif (-not $ReplaceOnly)
{
Write-Verbose "Adding configuration Key ""$Key"" to configuration file ""$Path"" using Value ""$Value"""
Add-Content -Path $Path -Value $("`n" + $Key + "=" + $Value)
}
else
{
Write-Warning "Key ""$Key"" not found in configuration file ""$Path"" and parameter ""ReplaceOnly"" has been specified therefore no work done"
}
}
I'd do this:
function setConfig( $file, $key, $value )
{
$regex = '^' + [regex]::escape($key) + '\s*=.+'
$replace = "$key = $value"
$old = get-content $file
$new = $old -replace $regex,$replace
if (compare-object $old $new)
{
Write-Host (compare-object $old $new | ft -auto | out-string) -ForegroundColor Yellow
$new | set-content $file
}
else {
$replace | add-content $file
Write-Host "$replace added to $file" -ForegroundColor Cyan
}
}
Edit: added a replacement bell, and a not match whistle.
Change the function to this:
function Set-Config( $file, $key, $value )
{
$regreplace = $("(?<=$key).*?=.*")
$regvalue = $(" = " + $value)
if (([regex]::Match((Get-Content $file),$regreplace)).success) {
(Get-Content $file) `
|Foreach-Object { [regex]::Replace($_,$regreplace,$regvalue)
} | Set-Content $file
} else {
Add-Content -Path $file -Value $("`n" + $key + " = " + $value)
}
}
Then when you call the function, use this format:
Set-Config -file "divider.conf" -key "Logentrytimeout" -value "180"
Edit: I forgot your requirement of adding the line if it doesn't exist. This will check for the $key, if it exists it will set its value to $value. If it doesn't exist it will add $key = $value to the end of the file. I also renamed the function to be more consistent with power shell naming conventions.
#CarlR Function it's for PowerShell Version 3. This it's the same adapted to PowerShell Version 2.
EDIT: Changed regular expression to fix two bugs on Set-FileConfigurationValue:
If you have one line like this:
; This is a Black line
And you try to do:
Set-FileConfigurationValue $configFile "Black" 20 -ReplaceExistingValue
You get one message about "Replacing" but nothing happens.
If you have two lines like these:
filesTmp=50
Tmp=50
And you try to do:
Set-FileConfigurationValue $configFile "Tmp" 20 -ReplaceExistingValue
You get the two lines changed!
filesTmp=20
Tmp=20
This is the final version:
Function Set-FileConfigurationValue()
{
[CmdletBinding()]
param(
[Parameter(Mandatory=$True)]
[ValidateScript({Test-Path $_})]
[string] $Path,
[Parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[string] $Key,
[Parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[string]$Value,
[Switch] $ReplaceExistingValue,
[Switch] $ReplaceOnly
)
$regmatch= $("^($Key\s*=\s*)(.*)")
$regreplace=$('${1}'+$Value)
if ((Get-Content $Path) -match $regmatch)
{
If ($ReplaceExistingValue)
{
Write-Verbose "Replacing configuration Key ""$Key"" in configuration file ""$Path"" with Value ""$Value"""
(Get-Content -Path $Path) | ForEach-Object { $_ -replace $regmatch,$regreplace } | Set-Content $Path
}
else
{
Write-Warning "Key ""$Key"" found in configuration file ""$Path"". To replace this Value specify parameter ""ReplaceExistingValue"""
}
}
elseif (-not $ReplaceOnly)
{
Write-Verbose "Adding configuration Key ""$Key"" to configuration file ""$Path"" using Value ""$Value"""
Add-Content -Path $Path -Value $("`n" + $Key + "=" + $Value)
}
else
{
Write-Warning "Key ""$Key"" not found in configuration file ""$Path"" and parameter ""ReplaceOnly"" has been specified therefore no work done"
}
}
I've also added a function to read from the config file
Function Get-FileConfigurationValue()
{
[CmdletBinding()]
param(
[Parameter(Mandatory=$True)]
[ValidateScript({Test-Path $_})]
[string] $Path,
[Parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[string] $Key,
[Parameter(Mandatory=$False)]
[ValidateNotNullOrEmpty()]
[string]$Default=""
)
# Don't have spaces before key.
# To allow spaces, use "$Key\s*=\s*(.*)"
$regKey = $("^$Key\s*=\s*(.*)")
# Get only last time
$Value = Get-Content -Path $Path | Where {$_ -match $regKey} | Select-Object -last 1 | ForEach-Object { $matches[1] }
if(!$Value) { $Value=$Default }
Return $Value
}
function sed($filespec, $search, $replace)
{
foreach ($file in gci -Recurse $filespec | ? { Select-String $search $_ -Quiet } )
{
(gc $file) |
ForEach-Object {$_ -replace $search, $replace } |
Set-Content $file
}
}
Usage:
sed ".\*.config" "intranet-" "intranetsvcs-"