System.Type.GetCustomAttributes on an assembly loaded from a network share is not showing all attributes - code-access-security

I have a managed dll – repro.dll, which contains class TestModuleCommand decorated with 2 attributes: System.ObsoleteAttribute and System.Management.Automation.CmdletAttribute (comes from System.Management.Automation.dll which is in the GAC in Windows 7)
namespace Test {
[System.Obsolete]
[System.Management.Automation.Cmdlet("Test", "Module")]
public class TestModuleCommand : System.Management.Automation.PSCmdlet {
protected override void ProcessRecord() {
this.WriteObject("In test-module");
}
}
}
If repro.dll is placed in a local directory, I can see both attributes returned from System.Type.GetCustomAttributes(false). If repro.dll is placed in a network path, then I can see only one attribute (although I still see both attributes via System.Reflection.CustomAttributeData.GetCustomAttributes(MemberInfo)). This is undesired – I want to see both attributes (I know that instantiating CmdletAttribute doesn’t have a security impact).
From what I found online, I am vaguely aware that repro.dll (if loaded from network location) cannot fully see S.M.A.dll. I think that CAS allows me to declare in System.Management.Automation that CmdletAttribute is safe, but I haven’t been able to figure out how to write that declaration. Where can I read more to fully understand what is going on? Any words of wisdom are welcomed.
Thanks,
Lukasz
PS. Below is a repro that anyone can try at a powershell.exe prompt (in Windows 7 - Add-Type cmdlet is new in PowerShell v2):
PS C:\> Add-Type -TypeDefinition #"
>> namespace Test {
>> [System.Obsolete]
>> [System.Management.Automation.Cmdlet("Test", "Module")]
>> public class TestModuleCommand : System.Management.Automation.PSCmdlet {
>> protected override void ProcessRecord() {
>> this.WriteObject("In test-module");
>> }
>> }
>> }
>> "# -OutputAssembly \\axp-test\scratch\lukasza\repro.dll -OutputType Library
>>
PS C:\> # local copy would work...
PS C:\> # Copy \\axp-test\scratch\lukasza\repro.dll ~\repro.dll
PS C:\>
PS C:\> $a = [System.Reflection.Assembly]::LoadFrom("\\axp-test\scratch\lukasza\repro.dll")
PS C:\> $t = $a.GetType("Test.TestModuleCommand")
PS C:\> $t.GetCustomAttributes($false) # only 1 attribute is visible here
Message IsError TypeId
------- ------- ------
False System.ObsoleteAttribute
PS C:\>
PS C:\> [System.Reflection.CustomAttributeData]::GetCustomAttributes($t) # but I can see both attributes here
Constructor ConstructorArguments NamedArguments
----------- -------------------- --------------
Void .ctor(System.String, System.Str... {"Test", "Module"} {}
Void .ctor() {} {}
PS C:\>
PS C:\> $a.Evidence
SecurityZone
------------
Intranet

This is the answer that I found: Haibo Luo - My Attribute Disappears

Related

Select all alias on modifySSLConfig using JACL script

I would want to edit all of the SSL configurations on all of my alias. I have found some resources to do this and my code so far is
$AdminTask modifySSLConfig {-alias NodeDefaultSSLSettings -sslProtocol TLSv1.2}
$AdminConfig save
I would want to be able to do this on all of the alias that can be found on my server, but I don't know how
Any ideas or leads on how to do this will help. Thank you.
Edit:
I am now able to find all of the SSL configs by using this code
[$AdminTask listSSLConfigs {-scopeName (cell):Node01Cell:(node):Node01}
My next problem is, how would I be able to extract the alias string from there? I would only need the alias so that I can replace it on another variable so that I can just use a foreach loop for this
$AdminTask modifySSLConfig {-alias ${aliasvariablegoeshere} -sslProtocol TLSv1.2}
EDIT :
set hold [list [$AdminTask listSSLConfigs {-scopeName (cell):Node01Cell:(node):Node01}]]
foreach aliasList [$AdminConfig show $hold] {
foreach aliasName [$AdminConfig show $aliasList] {
set testTrim "alias "
set test5 [string trimleft $aliasName $testTrim]
$AdminTask modifySSLConfig {-alias ${test5} -sslProtocol TLSv1.2}
}
}
$AdminControl save
I have done this and was able to extract just the alias name and was able to put it on the variable like I wanted, but it gives me an invalid parameter error. Any ideas why this is happening and how would I be able to resolve this?
You can list all the SSL configs using:
AdminTask.listSSLConfigs('[-all true]')
for JACL use:
$AdminTask listSSLConfigs {-all true}
and then iterate over the list and change whatever you need.
Instead of -all you can provide scope for example: -scopeName (cell):localhostNode01Cell:(node):localhostNode01
For details about SSLConfig commands check SSLConfigCommands command group for the AdminTask object
UPDATE:
in general this should work:
foreach aliasList [$AdminTask listSSLConfigs {-scopeName (cell):PCCell1:(node):Node1}] {
puts $aliasList
set splitList [split $aliasList " "]
puts $splitList
set aliasname [lindex $splitList 1]
puts $aliasname
$AdminTask modifySSLConfig { -alias $aliasname -sslProtocol TLSv1.2 }
}
but I cannot make $AdminTask to correctly resolve $aliasname param...
Strongly suggest you to switch to jython. ;-)
I have managed to make it work, it seems like whatever I do I can't make the alias that I got to be a valid parameter so I made the whole thing as a string command instead. Here is my code.
foreach aliasList [$AdminConfig list SSLConfig] {
foreach aliasName [$AdminConfig show $aliasList alias] {
set strTrim "alias "
set strFinal [string trimleft $aliasName $strTrim]
set command "-alias $strFinal -sslProtocol TLSv1.2"
$AdminTask modifySSLConfig $command
puts saved
}
}
$AdminConfig save
I was able to figure it out for Jython:
import sys
import os
import string
import re
#$HOME/IBM/WebSphere/AppServer/bin/wsadmin.sh -lang jython -f $HOME/tls12.py
#Updates Websphere security to TLSv1.2
AdminTask.convertCertForSecurityStandard('[-fipsLevel SP800-131 -signatureAlgorithm SHA256withRSA -keySize 2048 ]')
AdminConfig.save()
AdminNodeManagement.syncActiveNodes()
sslConfigList=AdminTask.listSSLConfigs('[-all true]').splitlines()
for sslConfig in sslConfigList:
sslElems=sslConfig.split(" ")
AdminTask.modifySSLConfig (['-alias',sslElems[1],'-scopeName',sslElems[3],'-sslProtocol', 'TLSv1.2', '-securityLevel', 'HIGH' ])
AdminConfig.save()
AdminNodeManagement.syncActiveNodes()
After that you should also update all your ssl.client.props files with:
com.ibm.ssl.protocol=TLSv1.2
Restart your deployment manager and force manual syncNode on all nodes, for example:
~/IBM/WebSphere/AppServer/profiles/*/bin/syncNode.sh <DeplymentManagerHost> <dmgr port=8879> -username <username> -password <password>

PowerShell - how to add private members?

In PowerShell (v2), how do you add private members to a PSObject?
That is, members that can only be accessed via $this from within a ScriptProperty or ScriptMethod.
Prior to the introduction of classes in version 5.0, the PowerShell extended type system (ETS) doesn't have the same concept of access modifiers as the underlying type system (.NET/CTS) has.
One way of hinting at "don't use this directly" to users, would be to have a prefix for "internal" properties, like __ (double underscore):
$object = New-Object psobject -Property #{
Public = 4
__private = 9
} |Add-Member -MemberType ScriptProperty -Name Private -Value {
$this.__private
} -SecondValue {
param([int]$newValue)
if(($newValue % 3) -ne 0){
Write-Warning "Only multiples of 3 allowed"
} else {
$this.__private = $newValue
}
} -PassThru

How to have MSBuild quiet output but with error/warning summary

I'm simply trying to get no output from a build except the error/warning summary at the end. Not exactly a demanding task.
The command line:
msbuild.exe /nologo /verbosity:quiet /consoleloggerparameters:summary project.sln
As described here: http://msdn.microsoft.com/en-us/library/ms164311.aspx
It appears MSBuild isn't working as it should - there is no output at all. with /verbosity:normal there is tonnes of output and a useful error/warning summary at the end, is there any way of just not seeing the noise?
MSBuild reports version 12.0.21005.1 as distributed with Studio Express 2013.
late to the party, but MSBuild has the option /verbosity:quiet now and it doesn't print out anything beside error and warnings.
You can specify the following verbosity levels:
q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]
Documentation source: https://msdn.microsoft.com/en-us/library/ms164311.aspx
Use /consoleloggerparameters:ErrorsOnly or clp:ErrorsOnly to solve your problem.
I don't think there is a set of options thet matches what you want exactly. But since you're on the commandline anyway, using findstr/grep/tail and the likes is always a good option. Here's an example using powershell to display the summary and what comes after it
powershell -Command "msbuild.exe /nologo project.sln |
Select-String 'Build succeeded|failed' -Context 0, 100"
Another possibility is to use a custom logger, which is not hard as it sounds at first and there are tons of examples on the net. Plus it has the benefit you can get any custom output you want. Here's code to replicate the summary:
using System;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;
public class CustomLogger : Logger
{
private int warnings = 0;
private int errors = 0;
public override void Initialize( IEventSource eventSource )
{
eventSource.WarningRaised += ( s, e ) => ++warnings;
eventSource.ErrorRaised += ( s, e ) => ++errors;
eventSource.BuildFinished += ( s, e ) =>
{
Console.WriteLine( errors == 0 ? "Build succeeded." : "Build failed." );
Console.WriteLine( String.Format( " {0} Warning(s)", warnings ) );
Console.WriteLine( String.Format( " {0} Error(s)", errors ) );
};
}
}
Put this in a file CustomLogger.cs and compile it:
csc /t:library CustomLogger.cs /reference:Microsoft.Build.Utilities.v4.0.dll;Microsoft.Build.Framework.dll
which creates a CustomLogger dll file. Now use it like this:
msbuild /nologo /logger:CustomLogger.dll /noconsolelogger project.sln
Use /verbosity:minimal instead. This prints much less, but not nothing.

Upload a file to Sharepoint 2010 with powershell 2.0

I'm struggling since a couple of days to upload files to Sharepoint 2010 with powershell.
I'm on a win7 machine with powershell v2 trying to upload to a SP 2010 site.
I'm having 2 major issues
$Context.web value is always empty even after Executequery() and no
error is shown. My $Context variable gets the server version (14.x.x.x.x) but nothing more
$Context.Load($variable) which always returns the error Cannot find an overload for "Load" and the argument count: "1".
I copied Sharepoint DLLs to my Win7 machine and I import the reference to my script.
The below script is a mix of many parts I took from the net.
I'v already tried unsuccessfully to add an overload on the clientcontext defining Load method without Type parameter suggested in the following post
http://soerennielsen.wordpress.com/2013/08/25/use-csom-from-powershell/
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
$site = "https://Root-of-my-site"
$listname = "My-folder"
$context = New-Object Microsoft.SharePoint.Client.ClientContext($site)
[Microsoft.SharePoint.Client.Web]$web = $context.Web
[Microsoft.SharePoint.Client.List]$list = $web.Lists.GetByTitle($listName)
$Folder = "C:\temp\Certificates"
$List = $Context.Web.Lists.GetByTitle($listname)
Foreach ($File in (dir $Folder))
{
$FileCreationInfo = New-Object Microsoft.SharePoint.Client.FileCreationInformation
$FileCreationInfo.Overwrite = $true
$FileCreationInfo.Content = get-content -encoding byte -path $File.Fullname
$FileCreationInfo.URL = $File
$Upload = $List.RootFolder.Files.Add($FileCreationInfo)
$Context.Load($Upload)
$Context.ExecuteQuery()
}
The error is
Cannot find an overload for "Load" and the argument count: "1".
At C:\temp\uploadCertToSharepoint.ps1:48 char:14
+ $Context.Load <<<< ($Upload)
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
Can someone please help me sorting this issue?
I'll need to upload around 400 files with ad-hoc fields to a sharepoint site in a couple of weeks and at the moment I'm completely stuck. Running the script server side is unfortunately not possible.
Thanks,
Marco
This error occurs since ClientRuntimeContext.Load is a Generics Method:
public void Load<T>(
T clientObject,
params Expression<Func<T, Object>>[] retrievals
)
where T : ClientObject
and Generics methods are not supported natively in PowerShell (V1, V2) AFAIK.
The workaround is to invoke a generic methods using MethodInfo.MakeGenericMethod method as described in article Invoking Generic Methods on Non-Generic Classes in PowerShell
In case of ClientRuntimeContext.Load method, the following PS function could be used:
Function Invoke-LoadMethod() {
param(
$clientObjectInstance = $(throw “Please provide an Client Object instance on which to invoke the generic method”)
)
$ctx = $clientObjectInstance.Context
$load = [Microsoft.SharePoint.Client.ClientContext].GetMethod("Load")
$type = $clientObjectInstance.GetType()
$clientObjectLoad = $load.MakeGenericMethod($type)
$clientObjectLoad.Invoke($ctx,#($clientObjectInstance,$null))
}
Then, in your example the line:
$Context.Load($Upload)
could be replaced with this one:
Invoke-LoadMethod -clientObjectInstance $Upload
References
Invoking Generic Methods on Non-Generic Classes in PowerShell
Some tips and tricks of using SharePoint Client Object Model in
PowerShell. Part 1
It throws the error because in powershell 2.0 you cannot call generic method directly.
You need to create closed method using MakeGenericMethod. Try to use code below.
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
$site = "http://server"
$listname = "listName"
$Folder = "C:\PS\Test"
$context = New-Object Microsoft.SharePoint.Client.ClientContext($site)
[Microsoft.SharePoint.Client.Web]$web = $context.Web
[Microsoft.SharePoint.Client.List]$list = $web.Lists.GetByTitle($listName)
$method = $Context.GetType().GetMethod("Load")
$closedMethod = $method.MakeGenericMethod([Microsoft.SharePoint.Client.File])
Foreach ($File in (dir $Folder))
{
$FileCreationInfo = New-Object Microsoft.SharePoint.Client.FileCreationInformation
$FileCreationInfo.Overwrite = $true
$FileCreationInfo.Content = (get-content -encoding byte -path $File.Fullname)
$FileCreationInfo.URL = $File
$Upload = $List.RootFolder.Files.Add($FileCreationInfo)
$closedMethod.Invoke($Context, #($Upload, $null) )
$Context.ExecuteQuery()
}

How to create a dynamic variable in Powershell, sucha as date/time etc

Hi i am not exactly sure if my wording is right but i need a variable which contains current date/time whenever i write data to log ; how can i do that without initializing everytime.Currently everytime i need a update i use these both statements jointly.Is there an other way of doing this?
$DateTime = get-date | select datetime
Add-Content $LogFile -Value "$DateTime.DateTime: XXXXX"
please do let me know if any questions or clarifications regarding my question.
This script make the real Dynamic variable in Powershell ( Thanks to Lee Holmes and his Windows PowerShell Cookbook The Complete Guide to Scripting Microsoft's Command Shell, 3rd Edition)
##############################################################################
##
## New-DynamicVariable
##
## From Windows PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
##
##############################################################################
<#
.SYNOPSIS
Creates a variable that supports scripted actions for its getter and setter
.EXAMPLE
PS > .\New-DynamicVariable GLOBAL:WindowTitle `
-Getter { $host.UI.RawUI.WindowTitle } `
-Setter { $host.UI.RawUI.WindowTitle = $args[0] }
PS > $windowTitle
Administrator: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
PS > $windowTitle = "Test"
PS > $windowTitle
Test
#>
param(
## The name for the dynamic variable
[Parameter(Mandatory = $true)]
$Name,
## The scriptblock to invoke when getting the value of the variable
[Parameter(Mandatory = $true)]
[ScriptBlock] $Getter,
## The scriptblock to invoke when setting the value of the variable
[ScriptBlock] $Setter
)
Set-StrictMode -Version 3
Add-Type #"
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
namespace Lee.Holmes
{
public class DynamicVariable : PSVariable
{
public DynamicVariable(
string name,
ScriptBlock scriptGetter,
ScriptBlock scriptSetter)
: base(name, null, ScopedItemOptions.AllScope)
{
getter = scriptGetter;
setter = scriptSetter;
}
private ScriptBlock getter;
private ScriptBlock setter;
public override object Value
{
get
{
if(getter != null)
{
Collection<PSObject> results = getter.Invoke();
if(results.Count == 1)
{
return results[0];
}
else
{
PSObject[] returnResults =
new PSObject[results.Count];
results.CopyTo(returnResults, 0);
return returnResults;
}
}
else { return null; }
}
set
{
if(setter != null) { setter.Invoke(value); }
}
}
}
}
"#
## If we've already defined the variable, remove it.
if(Test-Path variable:\$name)
{
Remove-Item variable:\$name -Force
}
## Set the new variable, along with its getter and setter.
$executioncontext.SessionState.PSVariable.Set(
(New-Object Lee.Holmes.DynamicVariable $name,$getter,$setter))
There's a Set-StrictMode -Version 3 but you can set it as -Version 2 if you can load framework 4.0 in your powershell V2.0 session as explained Here
The use for the OP is:
New-DynamicVariable -Name GLOBAL:now -Getter { (get-date).datetime }
Here the Lee Holmes's evaluation (where it is clear what is the real flaw) about the method I used in my other answer:
Note
There are innovative solutions on the Internet that use PowerShell's debugging facilities to create a breakpoint that changes a variable's value whenever you attempt to read from it. While unique, this solution causes PowerShell to think that any scripts that rely on the variable are in debugging mode. This, unfortunately, prevents PowerShell from enabling some important performance optimizations in those scripts.
Why not use:
Add-Content $LogFile -Value "$((Get-Date).DateTime): XXXXX"
This gets the current datetime every time. Notice that it's inside $( ) which makes powershell run the expression(get the datetime) before inserting it into the string.
wrap your two commands in function so you will have just one call ?
function add-log{
(param $txt)
$DateTime = get-date | select -expand datetime
Add-Content $LogFile -Value "$DateTime: $txt"
}
Besides these other ways (which frankly I would probably use instead - except the breakpoint approach), you can create a custom object with a ScriptProperty that you can provide the implementation for:
$obj = new-object pscustomobject
$obj | Add-Member ScriptProperty Now -Value { Get-Date }
$obj.now
Using PsBreakPoint:
$act= #'
$global:now = (get-date).datetime
'#
$global:sb = [scriptblock]::Create($act)
$now = Set-PSBreakpoint -Variable now -Mode Read -Action $global:sb
calling $now returns current updated datetime value
One liner:
$now = Set-PSBreakpoint -Variable now -Mode Read -Action { $global:now = (get-date).datetime }