Home All Groups Group Topic Archive Search About

Creating MSI for installing .NET security policies

Author
12 Oct 2006 2:38 PM
David++
Hi folks,

I'm deploying my app to a network share and I need the security permissions
installed on the client. AFAICT I cannot use ClickOnce because ClickOnce
deployment doesnt allow user to specify install location i.e. Network share.
So I have gone down the route of creating a Strong Name key and signing my
assemblies with that key, creating a new Code Group in the Microsoft .NET
configuration Tool which assigns full trust to my Strong Name key, and then
finally creating a deployment package MSI to allow users to install the
Security Policy easily.

Now, this all works ok, but I find it a bit sas that the security policies
are over written in the Code Groups with the new settings i.e. they are not
merged with the existing groups. Luckily my clients have a clean slate of
policies anyway so I wasnt overwriting anyone elses, but what if some other
vendor had written an app for the client and had used the same approach, I
would scrub there policies, or vice versa someone could quite easily scrub
mine. Is this correct?

Of course policies could be manually added in, but this might be a pain if
there were a lot of users.

Or is there another way I have missed?

Thanks again,
David

Author
12 Oct 2006 2:11 PM
Dominick Baier
Hi,

no thats the default behavior. You should write an MSI installer with custom
install/uninstall actions to programmatically create the stuff for you.

System.Security.Policy has all the classes you need.

I can dig out some code if you need it.

---
Dominick Baier, DevelopMentor
http://www.leastprivilege.com

Show quoteHide quote
> Hi folks,
>
> I'm deploying my app to a network share and I need the security
> permissions installed on the client. AFAICT I cannot use ClickOnce
> because ClickOnce deployment doesnt allow user to specify install
> location i.e. Network share. So I have gone down the route of creating
> a Strong Name key and signing my assemblies with that key, creating a
> new Code Group in the Microsoft .NET configuration Tool which assigns
> full trust to my Strong Name key, and then finally creating a
> deployment package MSI to allow users to install the Security Policy
> easily.
>
> Now, this all works ok, but I find it a bit sas that the security
> policies are over written in the Code Groups with the new settings
> i.e. they are not merged with the existing groups. Luckily my clients
> have a clean slate of policies anyway so I wasnt overwriting anyone
> elses, but what if some other vendor had written an app for the client
> and had used the same approach, I would scrub there policies, or vice
> versa someone could quite easily scrub mine. Is this correct?
>
> Of course policies could be manually added in, but this might be a
> pain if there were a lot of users.
>
> Or is there another way I have missed?
>
> Thanks again,
> David
Author
12 Oct 2006 3:20 PM
David++
Hi Dominick,

Sounds good, any code snippets you can summon would be very useful, I will
also turn to the mighty google for this one also.

Best,
David

Show quoteHide quote
"Dominick Baier" wrote:

> Hi,
>
> no thats the default behavior. You should write an MSI installer with custom
> install/uninstall actions to programmatically create the stuff for you.
>
> System.Security.Policy has all the classes you need.
>
> I can dig out some code if you need it.
>
> ---
> Dominick Baier, DevelopMentor
> http://www.leastprivilege.com
>
> > Hi folks,
> >
> > I'm deploying my app to a network share and I need the security
> > permissions installed on the client. AFAICT I cannot use ClickOnce
> > because ClickOnce deployment doesnt allow user to specify install
> > location i.e. Network share. So I have gone down the route of creating
> > a Strong Name key and signing my assemblies with that key, creating a
> > new Code Group in the Microsoft .NET configuration Tool which assigns
> > full trust to my Strong Name key, and then finally creating a
> > deployment package MSI to allow users to install the Security Policy
> > easily.
> >
> > Now, this all works ok, but I find it a bit sas that the security
> > policies are over written in the Code Groups with the new settings
> > i.e. they are not merged with the existing groups. Luckily my clients
> > have a clean slate of policies anyway so I wasnt overwriting anyone
> > elses, but what if some other vendor had written an app for the client
> > and had used the same approach, I would scrub there policies, or vice
> > versa someone could quite easily scrub mine. Is this correct?
> >
> > Of course policies could be manually added in, but this might be a
> > pain if there were a lot of users.
> >
> > Or is there another way I have missed?
> >
> > Thanks again,
> > David
>
>
>
Author
12 Oct 2006 2:56 PM
Joe Kaplan
Probably the most reliable method would be to create a custom action that
calls caspol.exe with the proper arguments to add your policy to the current
policy.  You'll probably want to use a search of some sort to find the
appropriate .NET framework directory to use to call caspol so that you
configure for the correct framework version.

Joe K.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
--
Show quoteHide quote
"David++" <Da***@discussions.microsoft.com> wrote in message
news:EA689966-00ED-4B4D-A577-38776F91A1C6@microsoft.com...
> Hi folks,
>
> I'm deploying my app to a network share and I need the security
> permissions
> installed on the client. AFAICT I cannot use ClickOnce because ClickOnce
> deployment doesnt allow user to specify install location i.e. Network
> share.
> So I have gone down the route of creating a Strong Name key and signing my
> assemblies with that key, creating a new Code Group in the Microsoft .NET
> configuration Tool which assigns full trust to my Strong Name key, and
> then
> finally creating a deployment package MSI to allow users to install the
> Security Policy easily.
>
> Now, this all works ok, but I find it a bit sas that the security policies
> are over written in the Code Groups with the new settings i.e. they are
> not
> merged with the existing groups. Luckily my clients have a clean slate of
> policies anyway so I wasnt overwriting anyone elses, but what if some
> other
> vendor had written an app for the client and had used the same approach, I
> would scrub there policies, or vice versa someone could quite easily scrub
> mine. Is this correct?
>
> Of course policies could be manually added in, but this might be a pain if
> there were a lot of users.
>
> Or is there another way I have missed?
>
> Thanks again,
> David
Author
12 Oct 2006 2:16 PM
Dominick Baier
ouch...

use the API. Thats the most robust way.

---
Dominick Baier, DevelopMentor
http://www.leastprivilege.com

Show quoteHide quote
> Probably the most reliable method would be to create a custom action
> that calls caspol.exe with the proper arguments to add your policy to
> the current policy.  You'll probably want to use a search of some sort
> to find the appropriate .NET framework directory to use to call caspol
> so that you configure for the correct framework version.
>
> Joe K.
>
Author
12 Oct 2006 3:50 PM
Joe Kaplan
The poblem with that is that doing .NET code inside an MSI via a custom
action is a little painful as of now.  MSI doesn't have native support for
..NET custom actions, only script and native DLLs (or exe files).  There are
many hacks to support this, but they are all hacks for now and have a
variety of shortcomings.

I agree that the .NET classes are better in theory.

Joe K.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
--
Show quoteHide quote
"Dominick Baier" <dbaier@pleasepleasenospam_leastprivilege.com> wrote in
message news:4580be63196448c8bc30df997b80@news.microsoft.com...
> ouch...
>
> use the API. Thats the most robust way.
>
> ---
> Dominick Baier, DevelopMentor
> http://www.leastprivilege.com
>
>> Probably the most reliable method would be to create a custom action
>> that calls caspol.exe with the proper arguments to add your policy to
>> the current policy.  You'll probably want to use a search of some sort
>> to find the appropriate .NET framework directory to use to call caspol
>> so that you configure for the correct framework version.
>>
>> Joe K.
>>
>
>
Author
12 Oct 2006 2:59 PM
Dominick Baier
just create a installer project - add a class that derives from Installer
- override Install/Uninstall - where's the hack??

[RunInstaller(true)]
public class PolicyInstaller : Installer
{
    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.Container components = null;

    string permissionSetName = "Acme Permissions";
    string permissionSetDesc = "This is the set of permissions needed by
..NET applications for Acme corporation";
    string codeGroupName = "Acme Code Group";
    string codeGroupDesc = "Grants a few extra permissions to any assembly
signed with the Acme strong name";

    public PolicyInstaller()
    {
        // This call is required by the Designer.
        InitializeComponent();
    }

    #region Component Designer generated code
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        components = new System.ComponentModel.Container();
    }
    #endregion

    // this code will run when the MSI file is installed
    public override void Install(IDictionary stateSaver)
    {

        // first need to find the machine policy,
        // which is where we'll make our changes
        PolicyLevel machinePolicy = _findPolicyLevel(PolicyLevelType.Machine);

        if (null == machinePolicy)
        {
            // sanity check - this should never happen
            throw new ApplicationException("Failed to find the machine policy
in the PolicyHierarchy");
        }

        // we need to add a named permission set
        // that includes whatever permissions we're granting
        NamedPermissionSet nps = new NamedPermissionSet(permissionSetName,
PermissionState.None);
        nps.Description = permissionSetDesc;

        // TODO: add some permissions
        nps.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read,
@"c:\acme\expenses"));
        nps.AddPermission(new EnvironmentPermission(EnvironmentPermissionAccess.Read,
"EXPENSE"));
        nps.AddPermission(new SqlClientPermission(PermissionState.Unrestricted));
        nps.AddPermission(new DataProtectionPermission(PermissionState.Unrestricted));

        // add our named permission set to the machine policy level
        // note that nothing is saved yet (we'll save at the end)
        try
        {
            machinePolicy.AddNamedPermissionSet(nps);
        }
        catch
        {
            // duplicate name - update the existing one with the same name
            machinePolicy.ChangeNamedPermissionSet(nps.Name, nps);
        }

        // create code group
        CodeGroup cg = new UnionCodeGroup(
            new StrongNameMembershipCondition(
                new StrongNamePublicKeyBlob(acmePublicKey),
                null,   // match regardless of assembly's simple name
                null),  // match regardless of assembly's version
            new PolicyStatement(nps,
                PolicyStatementAttribute.Nothing) // no LevelFinal or Exclusive
attribute on this code group
            );
        cg.Name = codeGroupName;
        cg.Description = codeGroupDesc;

        // code groups with duplicate names are legal, but messy and confusing,
        // so we make sure to first remove any existing code groups with
our name
        _removeCodeGroupsByName(machinePolicy.RootCodeGroup, cg.Name);

        // add our new code group (note we've not saved yet).
        machinePolicy.RootCodeGroup.AddChild(cg);

        // finally, save all changes atomically.
        SecurityManager.SavePolicyLevel(machinePolicy);
    }

    // this code will run when our MSI is uninstalled
    public override void Uninstall(IDictionary savedState)
    {
        // first need to find the machine policy,
        // which is where we'll make our changes
        PolicyLevel machinePolicy = _findPolicyLevel(PolicyLevelType.Machine);

        if (null == machinePolicy)
        {
            // sanity check - this should never happen
            throw new ApplicationException("Failed to find the machine policy
in the PolicyHierarchy");
        }

        // remove our code group
        _removeCodeGroupsByName(machinePolicy.RootCodeGroup, codeGroupName);

        // remove our named permission set
        try
        {
            machinePolicy.RemoveNamedPermissionSet(permissionSetName);
        }
        catch
        {
            // if it's not there, no biggie - just doing our best to clean
up.
        }

        // finally, save all changes atomically.
        SecurityManager.SavePolicyLevel(machinePolicy);
    }

    PolicyLevel _findPolicyLevel(PolicyLevelType policyLevel)
    {
        IEnumerator policyLevelEnumerator = SecurityManager.PolicyHierarchy();
        PolicyLevel found = null;
        while (policyLevelEnumerator.MoveNext())
        {
            PolicyLevel lvl = (PolicyLevel)policyLevelEnumerator.Current;
            if (lvl.Type == policyLevel)
            {
                found = lvl;
            }
        }
        return found;
    }

    void _removeCodeGroupsByName(CodeGroup parent, string childName)
    {
        // the implementation of CodeGroup.Children (viewed with Anakrino)
        // gives a deep copy of the children, so technically this is overkill,
        // but the documentation doesn't guarantee this, so we enumerate
        // then delete in two separate steps as you would with any dynamic
list
        ArrayList codeGroupsToRemove = new ArrayList();
        foreach (CodeGroup existingCodeGroup in parent.Children)
        {
            if (childName == existingCodeGroup.Name)
            {
                codeGroupsToRemove.Add(existingCodeGroup);
            }
        }
        foreach (CodeGroup cg in codeGroupsToRemove)
        {
            parent.RemoveChild(cg);
        }
    }

    // public key from AcmeExpense.exe using the secutil tool
    byte[] acmePublicKey = new byte[]{ 0, 36, 0, 0, 4, 128, 0, 0, 148, 0,
0, 0,
                                         6, 2, 0, 0, 0, 36, 0, 0, 82, 83,
65, 49,
                                         0, 4, 0, 0, 1, 0, 1, 0, 85, 73,
181, 56,
                                         224, 255, 198, 167, 151, 206, 111,
135,
                                         63, 32, 172, 222, 77, 52, 224, 240,
213,
                                         218, 202, 79, 18, 100, 175, 171,
17, 242,
                                         83, 200, 243, 42, 105, 75, 231,
4, 81,
                                         164, 11, 105, 39, 193, 38, 32, 161,
246,
                                         131, 55, 86, 216, 252, 116, 204,
12, 60,
                                         91, 125, 46, 230, 95, 108, 13, 161,
34,
                                         69, 98, 191, 236, 147, 208, 59,
80, 172,
                                         98, 1, 213, 167, 105, 180, 135,
22, 231,
                                         69, 11, 55, 252, 224, 212, 219,
86, 112,
                                         32, 92, 118, 40, 250, 51, 173, 23,
33,
                                         77, 179, 133, 49, 197, 137, 174,
236,
                                         57, 143, 37, 244, 251, 98, 178,
255, 175,
                                         135, 107, 5, 168, 106, 175, 184,
116, 206 };
}


---
Dominick Baier, DevelopMentor
http://www.leastprivilege.com

Show quoteHide quote
> The poblem with that is that doing .NET code inside an MSI via a
> custom action is a little painful as of now.  MSI doesn't have native
> support for .NET custom actions, only script and native DLLs (or exe
> files).  There are many hacks to support this, but they are all hacks
> for now and have a variety of shortcomings.
>
> I agree that the .NET classes are better in theory.
>
> Joe K.
>
Author
12 Oct 2006 5:13 PM
Joe Kaplan
Only MSI packages created in VS.NET have native support for Installer
classes via custom actions, and that is actually implemented via a hackfest
shim that the VS team put into their code base.  Installer classes are
generally regarded as "the devil" by professional setup authors, as they
violate some key MSI principles and have really poor integration with MSI in
general.  They are regarded as "toys for devs", but not for serious setup
authors.

The fact that the VS team continues to push Installer classes as the way to
do things is a source of tension with the Windows Installer guys at MS.

I know all of this stuff as I've been dragged into the world of doing more
"pro" setup development for a project after hitting the wall with the
capabilities of VS.NET deployment projects and found out about the dark side
of Installer classes.

Joe K.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
--
Show quoteHide quote
"Dominick Baier" <dbaier@pleasepleasenospam_leastprivilege.com> wrote in
message news:4580be63196508c8bc36e25f27d0@news.microsoft.com...
> just create a installer project - add a class that derives from
> Installer - override Install/Uninstall - where's the hack??
>
> [RunInstaller(true)]
> public class PolicyInstaller : Installer
> {
>    /// <summary>
>    /// Required designer variable.
>    /// </summary>
>    private System.ComponentModel.Container components = null;
>
>    string permissionSetName = "Acme Permissions";
>    string permissionSetDesc = "This is the set of permissions needed by
> .NET applications for Acme corporation";
>    string codeGroupName = "Acme Code Group";
>    string codeGroupDesc = "Grants a few extra permissions to any assembly
> signed with the Acme strong name";
>
>    public PolicyInstaller()
>    {
>        // This call is required by the Designer.
>        InitializeComponent();
>    }
>
>    #region Component Designer generated code
>    /// <summary>
>    /// Required method for Designer support - do not modify
>    /// the contents of this method with the code editor.
>    /// </summary>
>    private void InitializeComponent()
>    {
>        components = new System.ComponentModel.Container();
>    }
>    #endregion
>
>    // this code will run when the MSI file is installed
>    public override void Install(IDictionary stateSaver)
>    {
>
>        // first need to find the machine policy,
>        // which is where we'll make our changes
>        PolicyLevel machinePolicy =
> _findPolicyLevel(PolicyLevelType.Machine);
>
>        if (null == machinePolicy)
>        {
>            // sanity check - this should never happen
>            throw new ApplicationException("Failed to find the machine
> policy in the PolicyHierarchy");
>        }
>
>        // we need to add a named permission set
>        // that includes whatever permissions we're granting
>        NamedPermissionSet nps = new NamedPermissionSet(permissionSetName,
> PermissionState.None);
>        nps.Description = permissionSetDesc;
>
>        // TODO: add some permissions
>        nps.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read,
> @"c:\acme\expenses"));
>        nps.AddPermission(new
> EnvironmentPermission(EnvironmentPermissionAccess.Read, "EXPENSE"));
>        nps.AddPermission(new
> SqlClientPermission(PermissionState.Unrestricted));
>        nps.AddPermission(new
> DataProtectionPermission(PermissionState.Unrestricted));
>
>        // add our named permission set to the machine policy level
>        // note that nothing is saved yet (we'll save at the end)
>        try
>        {
>            machinePolicy.AddNamedPermissionSet(nps);
>        }
>        catch
>        {
>            // duplicate name - update the existing one with the same name
>            machinePolicy.ChangeNamedPermissionSet(nps.Name, nps);
>        }
>
>        // create code group
>        CodeGroup cg = new UnionCodeGroup(
>            new StrongNameMembershipCondition(
>                new StrongNamePublicKeyBlob(acmePublicKey),
>                null,   // match regardless of assembly's simple name
>                null),  // match regardless of assembly's version
>            new PolicyStatement(nps,
>                PolicyStatementAttribute.Nothing) // no LevelFinal or
> Exclusive attribute on this code group
>            );
>        cg.Name = codeGroupName;
>        cg.Description = codeGroupDesc;
>
>        // code groups with duplicate names are legal, but messy and
> confusing,
>        // so we make sure to first remove any existing code groups with
> our name
>        _removeCodeGroupsByName(machinePolicy.RootCodeGroup, cg.Name);
>
>        // add our new code group (note we've not saved yet).
>        machinePolicy.RootCodeGroup.AddChild(cg);
>
>        // finally, save all changes atomically.
>        SecurityManager.SavePolicyLevel(machinePolicy);
>    }
>
>    // this code will run when our MSI is uninstalled
>    public override void Uninstall(IDictionary savedState)
>    {
>        // first need to find the machine policy,
>        // which is where we'll make our changes
>        PolicyLevel machinePolicy =
> _findPolicyLevel(PolicyLevelType.Machine);
>
>        if (null == machinePolicy)
>        {
>            // sanity check - this should never happen
>            throw new ApplicationException("Failed to find the machine
> policy in the PolicyHierarchy");
>        }
>
>        // remove our code group
>        _removeCodeGroupsByName(machinePolicy.RootCodeGroup,
> codeGroupName);
>
>        // remove our named permission set
>        try
>        {
>            machinePolicy.RemoveNamedPermissionSet(permissionSetName);
>        }
>        catch
>        {
>            // if it's not there, no biggie - just doing our best to clean
> up.
>        }
>
>        // finally, save all changes atomically.
>        SecurityManager.SavePolicyLevel(machinePolicy);
>    }
>
>    PolicyLevel _findPolicyLevel(PolicyLevelType policyLevel)
>    {
>        IEnumerator policyLevelEnumerator =
> SecurityManager.PolicyHierarchy();
>        PolicyLevel found = null;
>        while (policyLevelEnumerator.MoveNext())
>        {
>            PolicyLevel lvl = (PolicyLevel)policyLevelEnumerator.Current;
>            if (lvl.Type == policyLevel)
>            {
>                found = lvl;
>            }
>        }
>        return found;
>    }
>
>    void _removeCodeGroupsByName(CodeGroup parent, string childName)
>    {
>        // the implementation of CodeGroup.Children (viewed with Anakrino)
>        // gives a deep copy of the children, so technically this is
> overkill,
>        // but the documentation doesn't guarantee this, so we enumerate
>        // then delete in two separate steps as you would with any dynamic
> list
>        ArrayList codeGroupsToRemove = new ArrayList();
>        foreach (CodeGroup existingCodeGroup in parent.Children)
>        {
>            if (childName == existingCodeGroup.Name)
>            {
>                codeGroupsToRemove.Add(existingCodeGroup);
>            }
>        }
>        foreach (CodeGroup cg in codeGroupsToRemove)
>        {
>            parent.RemoveChild(cg);
>        }
>    }
>
>    // public key from AcmeExpense.exe using the secutil tool
>    byte[] acmePublicKey = new byte[]{ 0, 36, 0, 0, 4, 128, 0, 0, 148, 0,
> 0, 0,
>                                         6, 2, 0, 0, 0, 36, 0, 0, 82, 83,
> 65, 49, 0, 4, 0, 0, 1, 0, 1, 0, 85, 73, 181, 56, 224, 255, 198, 167, 151,
> 206, 111, 135,
>                                         63, 32, 172, 222, 77, 52, 224,
> 240, 213,
>                                         218, 202, 79, 18, 100, 175, 171,
> 17, 242,
>                                         83, 200, 243, 42, 105, 75, 231, 4,
> 81, 164, 11, 105, 39, 193, 38, 32, 161, 246,
>                                         131, 55, 86, 216, 252, 116, 204,
> 12, 60,
>                                         91, 125, 46, 230, 95, 108, 13,
> 161, 34, 69, 98, 191, 236, 147, 208, 59, 80, 172,
>                                         98, 1, 213, 167, 105, 180, 135,
> 22, 231,
>                                         69, 11, 55, 252, 224, 212, 219,
> 86, 112,
>                                         32, 92, 118, 40, 250, 51, 173, 23,
> 33, 77, 179, 133, 49, 197, 137, 174, 236, 57, 143, 37, 244, 251, 98, 178,
> 255, 175,
>                                         135, 107, 5, 168, 106, 175, 184,
> 116, 206 };
> }
>
>
> ---
> Dominick Baier, DevelopMentor
> http://www.leastprivilege.com
>
>> The poblem with that is that doing .NET code inside an MSI via a
>> custom action is a little painful as of now.  MSI doesn't have native
>> support for .NET custom actions, only script and native DLLs (or exe
>> files).  There are many hacks to support this, but they are all hacks
>> for now and have a variety of shortcomings.
>>
>> I agree that the .NET classes are better in theory.
>>
>> Joe K.
>>
>
>
>
Author
12 Oct 2006 4:49 PM
Dominick Baier
OK :)

but for the purpose of having a robust way to install/uninstall policies
they are perfect (for me).

---
Dominick Baier, DevelopMentor
http://www.leastprivilege.com

Show quoteHide quote
> Only MSI packages created in VS.NET have native support for Installer
> classes via custom actions, and that is actually implemented via a
> hackfest shim that the VS team put into their code base.  Installer
> classes are generally regarded as "the devil" by professional setup
> authors, as they violate some key MSI principles and have really poor
> integration with MSI in general.  They are regarded as "toys for
> devs", but not for serious setup authors.
>
> The fact that the VS team continues to push Installer classes as the
> way to do things is a source of tension with the Windows Installer
> guys at MS.
>
> I know all of this stuff as I've been dragged into the world of doing
> more "pro" setup development for a project after hitting the wall with
> the capabilities of VS.NET deployment projects and found out about the
> dark side of Installer classes.
>
> Joe K.
>
Author
12 Oct 2006 8:31 PM
Joe Kaplan
Yep, it is really all about the audience in this case.  They are great for
devs and not so great for people doing professional deployment packaging.

Ideally, MS would fix this mess and create a solution that worked well for
both.  The current implementation is not well-conceived and leads to this
tension.  It could be a much better for both audiences.

Joe K.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
--
Show quoteHide quote
"Dominick Baier" <dbaier@pleasepleasenospam_leastprivilege.com> wrote in
message news:4580be63196598c8bc4646b1f770@news.microsoft.com...
> OK :)
>
> but for the purpose of having a robust way to install/uninstall policies
> they are perfect (for me).
>
> ---
> Dominick Baier, DevelopMentor
> http://www.leastprivilege.com
>
>> Only MSI packages created in VS.NET have native support for Installer
>> classes via custom actions, and that is actually implemented via a
>> hackfest shim that the VS team put into their code base.  Installer
>> classes are generally regarded as "the devil" by professional setup
>> authors, as they violate some key MSI principles and have really poor
>> integration with MSI in general.  They are regarded as "toys for
>> devs", but not for serious setup authors.
>>
>> The fact that the VS team continues to push Installer classes as the
>> way to do things is a source of tension with the Windows Installer
>> guys at MS.
>>
>> I know all of this stuff as I've been dragged into the world of doing
>> more "pro" setup development for a project after hitting the wall with
>> the capabilities of VS.NET deployment projects and found out about the
>> dark side of Installer classes.
>>
>> Joe K.
>>
>
>
Author
12 Oct 2006 3:15 PM
David++
Hi Joe,

Thanks for the reply. That sounds like a good way of doing it. I'll give it
a shot.

Cheers very much,
David

Show quoteHide quote
"Joe Kaplan" wrote:

> Probably the most reliable method would be to create a custom action that
> calls caspol.exe with the proper arguments to add your policy to the current
> policy.  You'll probably want to use a search of some sort to find the
> appropriate .NET framework directory to use to call caspol so that you
> configure for the correct framework version.
>
> Joe K.
>
> --
> Joe Kaplan-MS MVP Directory Services Programming
> Co-author of "The .NET Developer's Guide to Directory Services Programming"
> http://www.directoryprogramming.net
> --
> "David++" <Da***@discussions.microsoft.com> wrote in message
> news:EA689966-00ED-4B4D-A577-38776F91A1C6@microsoft.com...
> > Hi folks,
> >
> > I'm deploying my app to a network share and I need the security
> > permissions
> > installed on the client. AFAICT I cannot use ClickOnce because ClickOnce
> > deployment doesnt allow user to specify install location i.e. Network
> > share.
> > So I have gone down the route of creating a Strong Name key and signing my
> > assemblies with that key, creating a new Code Group in the Microsoft .NET
> > configuration Tool which assigns full trust to my Strong Name key, and
> > then
> > finally creating a deployment package MSI to allow users to install the
> > Security Policy easily.
> >
> > Now, this all works ok, but I find it a bit sas that the security policies
> > are over written in the Code Groups with the new settings i.e. they are
> > not
> > merged with the existing groups. Luckily my clients have a clean slate of
> > policies anyway so I wasnt overwriting anyone elses, but what if some
> > other
> > vendor had written an app for the client and had used the same approach, I
> > would scrub there policies, or vice versa someone could quite easily scrub
> > mine. Is this correct?
> >
> > Of course policies could be manually added in, but this might be a pain if
> > there were a lot of users.
> >
> > Or is there another way I have missed?
> >
> > Thanks again,
> > David
>
>
>